From 025d5a7cbfa1d4e17a17b34e48de3e2a6cb6317b Mon Sep 17 00:00:00 2001 From: Nasr Date: Mon, 18 Nov 2024 10:07:48 +0700 Subject: [PATCH 01/11] sqlx types for erc --- crates/torii/core/src/types.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crates/torii/core/src/types.rs b/crates/torii/core/src/types.rs index be120e50ad..a444a0d679 100644 --- a/crates/torii/core/src/types.rs +++ b/crates/torii/core/src/types.rs @@ -121,6 +121,27 @@ pub struct Event { pub executed_at: DateTime, pub created_at: DateTime, } + +#[derive(FromRow, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ContractMetadata { + pub id: String, + pub contract_address: String, + pub name: String, + pub symbol: String, + pub decimals: u8, +} + +#[derive(FromRow, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Balance { + pub id: String, + pub balance: String, + pub account_address: String, + pub contract_address: String, + pub token_id: String, +} + #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)] pub struct Contract { pub address: Felt, From a19f1f2e57cccd5d7e31f1f3c70823803e7c6c56 Mon Sep 17 00:00:00 2001 From: Nasr Date: Mon, 18 Nov 2024 10:16:20 +0700 Subject: [PATCH 02/11] add to proto --- crates/torii/grpc/proto/types.proto | 14 ++++++++++++++ crates/torii/grpc/proto/world.proto | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/crates/torii/grpc/proto/types.proto b/crates/torii/grpc/proto/types.proto index 6b2abb2ba1..f2ad224d91 100644 --- a/crates/torii/grpc/proto/types.proto +++ b/crates/torii/grpc/proto/types.proto @@ -149,4 +149,18 @@ enum ComparisonOperator { GTE = 3; LT = 4; LTE = 5; +} + +message Token { + string contract_address = 2; + string name = 3; + string symbol = 4; + uint32 decimals = 5; +} + +message Balance { + string balance = 1; + string account_address = 2; + string contract_address = 3; + string token_id = 4; } \ No newline at end of file diff --git a/crates/torii/grpc/proto/world.proto b/crates/torii/grpc/proto/world.proto index 4898c44b8e..ed3946e37d 100644 --- a/crates/torii/grpc/proto/world.proto +++ b/crates/torii/grpc/proto/world.proto @@ -42,6 +42,20 @@ service World { // Subscribe to events rpc SubscribeEvents (SubscribeEventsRequest) returns (stream SubscribeEventsResponse); + + // Retrieve tokens + rpc RetrieveTokens (RetrieveTokensRequest) returns (RetrieveTokensResponse); +} + +// A request to retrieve tokens +message RetrieveTokensRequest { + // The list of contract addresses to retrieve tokens for + repeated bytes contract_addresses = 1; +} + +// A response containing tokens +message RetrieveTokensResponse { + repeated types.Token tokens = 1; } // A request to subscribe to indexer updates. From a28545d2c77e4c3d5df896f6cd2ae3c305cc562a Mon Sep 17 00:00:00 2001 From: Nasr Date: Mon, 18 Nov 2024 11:48:11 +0700 Subject: [PATCH 03/11] retriefe tokens --- crates/torii/core/src/types.rs | 3 +- crates/torii/grpc/proto/types.proto | 1 + crates/torii/grpc/src/server/mod.rs | 45 ++++++++++++++++++++++++++--- crates/torii/grpc/src/types/mod.rs | 13 +++++++++ 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/crates/torii/core/src/types.rs b/crates/torii/core/src/types.rs index a444a0d679..bb12806672 100644 --- a/crates/torii/core/src/types.rs +++ b/crates/torii/core/src/types.rs @@ -124,12 +124,13 @@ pub struct Event { #[derive(FromRow, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] -pub struct ContractMetadata { +pub struct Token { pub id: String, pub contract_address: String, pub name: String, pub symbol: String, pub decimals: u8, + pub metadata: String, } #[derive(FromRow, Deserialize, Debug, Clone)] diff --git a/crates/torii/grpc/proto/types.proto b/crates/torii/grpc/proto/types.proto index f2ad224d91..831133b060 100644 --- a/crates/torii/grpc/proto/types.proto +++ b/crates/torii/grpc/proto/types.proto @@ -156,6 +156,7 @@ message Token { string name = 3; string symbol = 4; uint32 decimals = 5; + string metadata = 6; } message Balance { diff --git a/crates/torii/grpc/src/server/mod.rs b/crates/torii/grpc/src/server/mod.rs index 858c4c523c..455edad7dc 100644 --- a/crates/torii/grpc/src/server/mod.rs +++ b/crates/torii/grpc/src/server/mod.rs @@ -43,6 +43,7 @@ use torii_core::error::{Error, ParseError, QueryError}; use torii_core::model::{build_sql_query, map_row_to_ty}; use torii_core::sql::cache::ModelCache; use torii_core::sql::utils::sql_string_to_felts; +use torii_core::types::Token; use tower_http::cors::{AllowOrigin, CorsLayer}; use self::subscriptions::entity::EntityManager; @@ -53,10 +54,7 @@ use crate::proto::types::member_value::ValueType; use crate::proto::types::LogicalOperator; use crate::proto::world::world_server::WorldServer; use crate::proto::world::{ - RetrieveEntitiesStreamingResponse, RetrieveEventMessagesRequest, SubscribeEntitiesRequest, - SubscribeEntityResponse, SubscribeEventMessagesRequest, SubscribeEventsResponse, - SubscribeIndexerRequest, SubscribeIndexerResponse, UpdateEventMessagesSubscriptionRequest, - WorldMetadataRequest, WorldMetadataResponse, + RetrieveEntitiesStreamingResponse, RetrieveEventMessagesRequest, RetrieveTokensRequest, RetrieveTokensResponse, SubscribeEntitiesRequest, SubscribeEntityResponse, SubscribeEventMessagesRequest, SubscribeEventsResponse, SubscribeIndexerRequest, SubscribeIndexerResponse, UpdateEventMessagesSubscriptionRequest, WorldMetadataRequest, WorldMetadataResponse }; use crate::proto::{self}; use crate::types::schema::SchemaError; @@ -789,6 +787,28 @@ impl DojoWorld { }) } + async fn retrieve_tokens( + &self, + contract_addresses: Vec, + ) -> Result { + let query = format!( + "SELECT * FROM tokens WHERE contract_address IN ({})", + contract_addresses + .iter() + .map(|address| format!("{:#x}", address)) + .collect::>() + .join(", ") + ); + + let tokens: Vec = sqlx::query_as(&query) + .fetch_all(&self.pool) + .await + .map_err(|e| Status::internal(e.to_string()))?; + + let tokens = tokens.iter().map(|token| token.clone().into()).collect(); + Ok(RetrieveTokensResponse { tokens }) + } + async fn subscribe_indexer( &self, contract_address: Felt, @@ -1165,6 +1185,23 @@ impl proto::world::world_server::World for DojoWorld { Ok(Response::new(WorldMetadataResponse { metadata })) } + async fn retrieve_tokens( + &self, + request: Request, + ) -> Result, Status> { + let RetrieveTokensRequest { contract_addresses } = request.into_inner(); + let contract_addresses = contract_addresses + .iter() + .map(|address| Felt::from_bytes_be_slice(address)) + .collect::>(); + + let tokens = self + .retrieve_tokens(contract_addresses) + .await + .map_err(|e| Status::internal(e.to_string()))?; + Ok(Response::new(tokens)) + } + async fn subscribe_indexer( &self, request: Request, diff --git a/crates/torii/grpc/src/types/mod.rs b/crates/torii/grpc/src/types/mod.rs index b4162f30b6..1c8a5390e0 100644 --- a/crates/torii/grpc/src/types/mod.rs +++ b/crates/torii/grpc/src/types/mod.rs @@ -10,12 +10,25 @@ use starknet::core::types::{ ContractStorageDiffItem, Felt, FromStrError, StateDiff, StateUpdate, StorageEntry, }; use strum_macros::{AsRefStr, EnumIter, FromRepr}; +use torii_core::types::Token; use crate::proto::types::member_value; use crate::proto::{self}; pub mod schema; +impl From for proto::types::Token { + fn from(value: Token) -> Self { + Self { + contract_address: value.contract_address, + name: value.name, + symbol: value.symbol, + decimals: value.decimals as u32, + metadata: serde_json::to_string(&value.metadata).unwrap(), + } + } +} + #[derive(Debug, Serialize, Deserialize, PartialEq, Hash, Eq, Clone)] pub struct IndexerUpdate { pub head: i64, From 78a341d421f16cceb21e1d4664e453485d466cca Mon Sep 17 00:00:00 2001 From: Nasr Date: Mon, 18 Nov 2024 14:04:20 +0700 Subject: [PATCH 04/11] retrieve token balances --- crates/torii/grpc/proto/types.proto | 2 +- crates/torii/grpc/proto/world.proto | 16 ++++++++++++++++ crates/torii/grpc/src/server/mod.rs | 8 ++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/torii/grpc/proto/types.proto b/crates/torii/grpc/proto/types.proto index 831133b060..d474065f63 100644 --- a/crates/torii/grpc/proto/types.proto +++ b/crates/torii/grpc/proto/types.proto @@ -159,7 +159,7 @@ message Token { string metadata = 6; } -message Balance { +message TokenBalance { string balance = 1; string account_address = 2; string contract_address = 3; diff --git a/crates/torii/grpc/proto/world.proto b/crates/torii/grpc/proto/world.proto index ed3946e37d..2c7e7b1270 100644 --- a/crates/torii/grpc/proto/world.proto +++ b/crates/torii/grpc/proto/world.proto @@ -45,6 +45,9 @@ service World { // Retrieve tokens rpc RetrieveTokens (RetrieveTokensRequest) returns (RetrieveTokensResponse); + + // Retrieve token balances + rpc RetrieveTokenBalances (RetrieveTokenBalancesRequest) returns (RetrieveTokenBalancesResponse); } // A request to retrieve tokens @@ -58,6 +61,19 @@ message RetrieveTokensResponse { repeated types.Token tokens = 1; } +// A request to retrieve token balances +message RetrieveTokenBalancesRequest { + // The account addresses to retrieve balances for + repeated bytes account_addresses = 1; + // The list of token contract addresses to retrieve balances for + repeated bytes contract_addresses = 2; +} + +// A response containing token balances +message RetrieveTokenBalancesResponse { + repeated types.TokenBalance balances = 1; +} + // A request to subscribe to indexer updates. message SubscribeIndexerRequest { bytes contract_address = 1; diff --git a/crates/torii/grpc/src/server/mod.rs b/crates/torii/grpc/src/server/mod.rs index 455edad7dc..3c92a74da4 100644 --- a/crates/torii/grpc/src/server/mod.rs +++ b/crates/torii/grpc/src/server/mod.rs @@ -809,6 +809,14 @@ impl DojoWorld { Ok(RetrieveTokensResponse { tokens }) } + async fn retrieve_balances( + &self, + account_address: Vec, + contract_addresses: Vec, + ) -> Result { + + } + async fn subscribe_indexer( &self, contract_address: Felt, From 4aece4ac7fb7c68097e029c111aaeb6bd399bd5f Mon Sep 17 00:00:00 2001 From: Nasr Date: Mon, 18 Nov 2024 14:49:58 +0700 Subject: [PATCH 05/11] finish up fetching for token balances --- crates/torii/core/src/types.rs | 2 +- crates/torii/grpc/src/server/mod.rs | 52 ++++++++++++++++++++++++++--- crates/torii/grpc/src/types/mod.rs | 13 +++++++- 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/crates/torii/core/src/types.rs b/crates/torii/core/src/types.rs index bb12806672..8c57e63cb6 100644 --- a/crates/torii/core/src/types.rs +++ b/crates/torii/core/src/types.rs @@ -135,7 +135,7 @@ pub struct Token { #[derive(FromRow, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] -pub struct Balance { +pub struct TokenBalance { pub id: String, pub balance: String, pub account_address: String, diff --git a/crates/torii/grpc/src/server/mod.rs b/crates/torii/grpc/src/server/mod.rs index 3c92a74da4..f15c276666 100644 --- a/crates/torii/grpc/src/server/mod.rs +++ b/crates/torii/grpc/src/server/mod.rs @@ -43,7 +43,7 @@ use torii_core::error::{Error, ParseError, QueryError}; use torii_core::model::{build_sql_query, map_row_to_ty}; use torii_core::sql::cache::ModelCache; use torii_core::sql::utils::sql_string_to_felts; -use torii_core::types::Token; +use torii_core::types::{Token, TokenBalance}; use tower_http::cors::{AllowOrigin, CorsLayer}; use self::subscriptions::entity::EntityManager; @@ -54,7 +54,7 @@ use crate::proto::types::member_value::ValueType; use crate::proto::types::LogicalOperator; use crate::proto::world::world_server::WorldServer; use crate::proto::world::{ - RetrieveEntitiesStreamingResponse, RetrieveEventMessagesRequest, RetrieveTokensRequest, RetrieveTokensResponse, SubscribeEntitiesRequest, SubscribeEntityResponse, SubscribeEventMessagesRequest, SubscribeEventsResponse, SubscribeIndexerRequest, SubscribeIndexerResponse, UpdateEventMessagesSubscriptionRequest, WorldMetadataRequest, WorldMetadataResponse + RetrieveEntitiesStreamingResponse, RetrieveEventMessagesRequest, RetrieveTokenBalancesRequest, RetrieveTokenBalancesResponse, RetrieveTokensRequest, RetrieveTokensResponse, SubscribeEntitiesRequest, SubscribeEntityResponse, SubscribeEventMessagesRequest, SubscribeEventsResponse, SubscribeIndexerRequest, SubscribeIndexerResponse, UpdateEventMessagesSubscriptionRequest, WorldMetadataRequest, WorldMetadataResponse }; use crate::proto::{self}; use crate::types::schema::SchemaError; @@ -809,12 +809,32 @@ impl DojoWorld { Ok(RetrieveTokensResponse { tokens }) } - async fn retrieve_balances( + async fn retrieve_token_balances( &self, - account_address: Vec, + account_addresses: Vec, contract_addresses: Vec, - ) -> Result { + ) -> Result { + let query = format!( + "SELECT * FROM token_balances WHERE account_address IN ({}) AND contract_address IN ({})", + account_addresses + .iter() + .map(|address| format!("{:#x}", address)) + .collect::>() + .join(", "), + contract_addresses + .iter() + .map(|address| format!("{:#x}", address)) + .collect::>() + .join(", ") + ); + + let balances: Vec = sqlx::query_as(&query) + .fetch_all(&self.pool) + .await + .map_err(|e| Status::internal(e.to_string()))?; + let balances = balances.iter().map(|balance| balance.clone().into()).collect(); + Ok(RetrieveTokenBalancesResponse { balances }) } async fn subscribe_indexer( @@ -1210,6 +1230,28 @@ impl proto::world::world_server::World for DojoWorld { Ok(Response::new(tokens)) } + async fn retrieve_token_balances( + &self, + request: Request, + ) -> Result, Status> { + let RetrieveTokenBalancesRequest { account_addresses, contract_addresses } = + request.into_inner(); + let account_addresses = account_addresses + .iter() + .map(|address| Felt::from_bytes_be_slice(address)) + .collect::>(); + let contract_addresses = contract_addresses + .iter() + .map(|address| Felt::from_bytes_be_slice(address)) + .collect::>(); + + let balances = self + .retrieve_token_balances(account_addresses, contract_addresses) + .await + .map_err(|e| Status::internal(e.to_string()))?; + Ok(Response::new(balances)) + } + async fn subscribe_indexer( &self, request: Request, diff --git a/crates/torii/grpc/src/types/mod.rs b/crates/torii/grpc/src/types/mod.rs index 1c8a5390e0..ffd93f495d 100644 --- a/crates/torii/grpc/src/types/mod.rs +++ b/crates/torii/grpc/src/types/mod.rs @@ -10,7 +10,7 @@ use starknet::core::types::{ ContractStorageDiffItem, Felt, FromStrError, StateDiff, StateUpdate, StorageEntry, }; use strum_macros::{AsRefStr, EnumIter, FromRepr}; -use torii_core::types::Token; +use torii_core::types::{Token, TokenBalance}; use crate::proto::types::member_value; use crate::proto::{self}; @@ -29,6 +29,17 @@ impl From for proto::types::Token { } } +impl From for proto::types::TokenBalance { + fn from(value: TokenBalance) -> Self { + Self { + balance: value.balance, + account_address: value.account_address, + contract_address: value.contract_address, + token_id: value.token_id, + } + } +} + #[derive(Debug, Serialize, Deserialize, PartialEq, Hash, Eq, Clone)] pub struct IndexerUpdate { pub head: i64, From e72bc0591bb4d504d3146307131fa626d895172c Mon Sep 17 00:00:00 2001 From: Nasr Date: Mon, 18 Nov 2024 15:20:55 +0700 Subject: [PATCH 06/11] fmt --- crates/torii/grpc/src/server/mod.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/torii/grpc/src/server/mod.rs b/crates/torii/grpc/src/server/mod.rs index f15c276666..9d0a9a617b 100644 --- a/crates/torii/grpc/src/server/mod.rs +++ b/crates/torii/grpc/src/server/mod.rs @@ -54,7 +54,11 @@ use crate::proto::types::member_value::ValueType; use crate::proto::types::LogicalOperator; use crate::proto::world::world_server::WorldServer; use crate::proto::world::{ - RetrieveEntitiesStreamingResponse, RetrieveEventMessagesRequest, RetrieveTokenBalancesRequest, RetrieveTokenBalancesResponse, RetrieveTokensRequest, RetrieveTokensResponse, SubscribeEntitiesRequest, SubscribeEntityResponse, SubscribeEventMessagesRequest, SubscribeEventsResponse, SubscribeIndexerRequest, SubscribeIndexerResponse, UpdateEventMessagesSubscriptionRequest, WorldMetadataRequest, WorldMetadataResponse + RetrieveEntitiesStreamingResponse, RetrieveEventMessagesRequest, RetrieveTokenBalancesRequest, + RetrieveTokenBalancesResponse, RetrieveTokensRequest, RetrieveTokensResponse, + SubscribeEntitiesRequest, SubscribeEntityResponse, SubscribeEventMessagesRequest, + SubscribeEventsResponse, SubscribeIndexerRequest, SubscribeIndexerResponse, + UpdateEventMessagesSubscriptionRequest, WorldMetadataRequest, WorldMetadataResponse, }; use crate::proto::{self}; use crate::types::schema::SchemaError; @@ -815,7 +819,8 @@ impl DojoWorld { contract_addresses: Vec, ) -> Result { let query = format!( - "SELECT * FROM token_balances WHERE account_address IN ({}) AND contract_address IN ({})", + "SELECT * FROM token_balances WHERE account_address IN ({}) AND contract_address IN \ + ({})", account_addresses .iter() .map(|address| format!("{:#x}", address)) From cd0528bba3282c04eb583a05562333fd348c0416 Mon Sep 17 00:00:00 2001 From: Nasr Date: Mon, 18 Nov 2024 15:38:01 +0700 Subject: [PATCH 07/11] wildcard conditions --- crates/torii/grpc/src/server/mod.rs | 55 +++++++++++++++++++---------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/crates/torii/grpc/src/server/mod.rs b/crates/torii/grpc/src/server/mod.rs index 9d0a9a617b..9d3bad48a6 100644 --- a/crates/torii/grpc/src/server/mod.rs +++ b/crates/torii/grpc/src/server/mod.rs @@ -795,14 +795,18 @@ impl DojoWorld { &self, contract_addresses: Vec, ) -> Result { - let query = format!( - "SELECT * FROM tokens WHERE contract_address IN ({})", - contract_addresses + let query = if contract_addresses.is_empty() { + "SELECT * FROM tokens".to_string() + } else { + format!( + "SELECT * FROM tokens WHERE contract_address IN ({})", + contract_addresses .iter() .map(|address| format!("{:#x}", address)) .collect::>() - .join(", ") - ); + .join(", ") + ) + }; let tokens: Vec = sqlx::query_as(&query) .fetch_all(&self.pool) @@ -818,20 +822,33 @@ impl DojoWorld { account_addresses: Vec, contract_addresses: Vec, ) -> Result { - let query = format!( - "SELECT * FROM token_balances WHERE account_address IN ({}) AND contract_address IN \ - ({})", - account_addresses - .iter() - .map(|address| format!("{:#x}", address)) - .collect::>() - .join(", "), - contract_addresses - .iter() - .map(|address| format!("{:#x}", address)) - .collect::>() - .join(", ") - ); + let mut query = "SELECT * FROM token_balances".to_string(); + + let mut conditions = Vec::new(); + if !account_addresses.is_empty() { + conditions.push(format!( + "account_address IN ({})", + account_addresses + .iter() + .map(|address| format!("{:#x}", address)) + .collect::>() + .join(", ") + )); + } + if !contract_addresses.is_empty() { + conditions.push(format!( + "contract_address IN ({})", + contract_addresses + .iter() + .map(|address| format!("{:#x}", address)) + .collect::>() + .join(", ") + )); + } + + if !conditions.is_empty() { + query += &format!(" WHERE {}", conditions.join(" AND ")); + } let balances: Vec = sqlx::query_as(&query) .fetch_all(&self.pool) From a4b8a2a0accc444b6c147bd4ab1555128232ca4c Mon Sep 17 00:00:00 2001 From: Nasr Date: Mon, 18 Nov 2024 15:38:22 +0700 Subject: [PATCH 08/11] fmt --- crates/torii/grpc/src/server/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/torii/grpc/src/server/mod.rs b/crates/torii/grpc/src/server/mod.rs index 9d3bad48a6..720f156d6a 100644 --- a/crates/torii/grpc/src/server/mod.rs +++ b/crates/torii/grpc/src/server/mod.rs @@ -801,9 +801,9 @@ impl DojoWorld { format!( "SELECT * FROM tokens WHERE contract_address IN ({})", contract_addresses - .iter() - .map(|address| format!("{:#x}", address)) - .collect::>() + .iter() + .map(|address| format!("{:#x}", address)) + .collect::>() .join(", ") ) }; From 52277da7bea48e204bf478ef3dd9dbe78fc94cc1 Mon Sep 17 00:00:00 2001 From: Nasr Date: Mon, 18 Nov 2024 16:48:01 +0700 Subject: [PATCH 09/11] fmt --- crates/torii/grpc/src/server/mod.rs | 23 +++++++++++++++++++++++ crates/torii/grpc/src/types/mod.rs | 24 ------------------------ 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/crates/torii/grpc/src/server/mod.rs b/crates/torii/grpc/src/server/mod.rs index 720f156d6a..23284c16d2 100644 --- a/crates/torii/grpc/src/server/mod.rs +++ b/crates/torii/grpc/src/server/mod.rs @@ -89,6 +89,29 @@ impl From for Error { } } +impl From for proto::types::Token { + fn from(value: Token) -> Self { + Self { + contract_address: value.contract_address, + name: value.name, + symbol: value.symbol, + decimals: value.decimals as u32, + metadata: serde_json::to_string(&value.metadata).unwrap(), + } + } +} + +impl From for proto::types::TokenBalance { + fn from(value: TokenBalance) -> Self { + Self { + balance: value.balance, + account_address: value.account_address, + contract_address: value.contract_address, + token_id: value.token_id, + } + } +} + #[derive(Debug, Clone)] pub struct DojoWorld { pool: Pool, diff --git a/crates/torii/grpc/src/types/mod.rs b/crates/torii/grpc/src/types/mod.rs index ffd93f495d..b4162f30b6 100644 --- a/crates/torii/grpc/src/types/mod.rs +++ b/crates/torii/grpc/src/types/mod.rs @@ -10,36 +10,12 @@ use starknet::core::types::{ ContractStorageDiffItem, Felt, FromStrError, StateDiff, StateUpdate, StorageEntry, }; use strum_macros::{AsRefStr, EnumIter, FromRepr}; -use torii_core::types::{Token, TokenBalance}; use crate::proto::types::member_value; use crate::proto::{self}; pub mod schema; -impl From for proto::types::Token { - fn from(value: Token) -> Self { - Self { - contract_address: value.contract_address, - name: value.name, - symbol: value.symbol, - decimals: value.decimals as u32, - metadata: serde_json::to_string(&value.metadata).unwrap(), - } - } -} - -impl From for proto::types::TokenBalance { - fn from(value: TokenBalance) -> Self { - Self { - balance: value.balance, - account_address: value.account_address, - contract_address: value.contract_address, - token_id: value.token_id, - } - } -} - #[derive(Debug, Serialize, Deserialize, PartialEq, Hash, Eq, Clone)] pub struct IndexerUpdate { pub head: i64, From 97b116565c98a83a27485f3cbdae7b8120dfef41 Mon Sep 17 00:00:00 2001 From: Nasr Date: Tue, 19 Nov 2024 11:31:11 +0700 Subject: [PATCH 10/11] add toek nbalances api to client --- crates/torii/client/src/client/mod.rs | 27 +++++++++++++-- crates/torii/grpc/src/client.rs | 49 ++++++++++++++++++++++++--- crates/torii/grpc/src/types/mod.rs | 44 ++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 7 deletions(-) diff --git a/crates/torii/client/src/client/mod.rs b/crates/torii/client/src/client/mod.rs index 391cad9ebb..7fa96c17ab 100644 --- a/crates/torii/client/src/client/mod.rs +++ b/crates/torii/client/src/client/mod.rs @@ -11,9 +11,12 @@ use starknet::providers::jsonrpc::HttpTransport; use starknet::providers::JsonRpcClient; use tokio::sync::RwLock as AsyncRwLock; use torii_grpc::client::{EntityUpdateStreaming, EventUpdateStreaming, IndexerUpdateStreaming}; -use torii_grpc::proto::world::{RetrieveEntitiesResponse, RetrieveEventsResponse}; +use torii_grpc::proto::world::{ + RetrieveEntitiesResponse, RetrieveEventsResponse, RetrieveTokenBalancesResponse, + RetrieveTokensResponse, +}; use torii_grpc::types::schema::Entity; -use torii_grpc::types::{EntityKeysClause, Event, EventQuery, Query}; +use torii_grpc::types::{EntityKeysClause, Event, EventQuery, Query, Token, TokenBalance}; use torii_relay::client::EventLoop; use torii_relay::types::Message; @@ -85,6 +88,26 @@ impl Client { self.metadata.read() } + /// Retrieves tokens matching contract addresses. + pub async fn tokens(&self, contract_addresses: Vec) -> Result, Error> { + let mut grpc_client = self.inner.write().await; + let RetrieveTokensResponse { tokens } = + grpc_client.retrieve_tokens(contract_addresses).await?; + Ok(tokens.into_iter().map(TryInto::try_into).collect::, _>>()?) + } + + /// Retrieves token balances for account addresses and contract addresses. + pub async fn token_balances( + &self, + account_addresses: Vec, + contract_addresses: Vec, + ) -> Result, Error> { + let mut grpc_client = self.inner.write().await; + let RetrieveTokenBalancesResponse { balances } = + grpc_client.retrieve_token_balances(account_addresses, contract_addresses).await?; + Ok(balances.into_iter().map(TryInto::try_into).collect::, _>>()?) + } + /// Retrieves entities matching query parameter. /// /// The query param includes an optional clause for filtering. Without clause, it fetches ALL diff --git a/crates/torii/grpc/src/client.rs b/crates/torii/grpc/src/client.rs index 3cbd3cbe75..f24d5f5f7e 100644 --- a/crates/torii/grpc/src/client.rs +++ b/crates/torii/grpc/src/client.rs @@ -11,11 +11,13 @@ use tonic::transport::Endpoint; use crate::proto::world::{ world_client, RetrieveEntitiesRequest, RetrieveEntitiesResponse, RetrieveEventMessagesRequest, - RetrieveEventsRequest, RetrieveEventsResponse, SubscribeEntitiesRequest, - SubscribeEntityResponse, SubscribeEventMessagesRequest, SubscribeEventsRequest, - SubscribeEventsResponse, SubscribeIndexerRequest, SubscribeIndexerResponse, - SubscribeModelsRequest, SubscribeModelsResponse, UpdateEntitiesSubscriptionRequest, - UpdateEventMessagesSubscriptionRequest, WorldMetadataRequest, + RetrieveEventsRequest, RetrieveEventsResponse, RetrieveTokenBalancesRequest, + RetrieveTokenBalancesResponse, RetrieveTokensRequest, RetrieveTokensResponse, + SubscribeEntitiesRequest, SubscribeEntityResponse, SubscribeEventMessagesRequest, + SubscribeEventsRequest, SubscribeEventsResponse, SubscribeIndexerRequest, + SubscribeIndexerResponse, SubscribeModelsRequest, SubscribeModelsResponse, + UpdateEntitiesSubscriptionRequest, UpdateEventMessagesSubscriptionRequest, + WorldMetadataRequest, }; use crate::types::schema::{Entity, SchemaError}; use crate::types::{EntityKeysClause, Event, EventQuery, IndexerUpdate, ModelKeysClause, Query}; @@ -90,6 +92,43 @@ impl WorldClient { .and_then(|metadata| metadata.try_into().map_err(Error::ParseStr)) } + pub async fn retrieve_tokens( + &mut self, + contract_addresses: Vec, + ) -> Result { + self.inner + .retrieve_tokens(RetrieveTokensRequest { + contract_addresses: contract_addresses + .into_iter() + .map(|c| c.to_bytes_be().to_vec()) + .collect(), + }) + .await + .map_err(Error::Grpc) + .map(|res| res.into_inner()) + } + + pub async fn retrieve_token_balances( + &mut self, + account_addresses: Vec, + contract_addresses: Vec, + ) -> Result { + self.inner + .retrieve_token_balances(RetrieveTokenBalancesRequest { + account_addresses: account_addresses + .into_iter() + .map(|a| a.to_bytes_be().to_vec()) + .collect(), + contract_addresses: contract_addresses + .into_iter() + .map(|c| c.to_bytes_be().to_vec()) + .collect(), + }) + .await + .map_err(Error::Grpc) + .map(|res| res.into_inner()) + } + pub async fn retrieve_entities( &mut self, query: Query, diff --git a/crates/torii/grpc/src/types/mod.rs b/crates/torii/grpc/src/types/mod.rs index b4162f30b6..0b1c18430c 100644 --- a/crates/torii/grpc/src/types/mod.rs +++ b/crates/torii/grpc/src/types/mod.rs @@ -2,9 +2,11 @@ use core::fmt; use std::collections::HashMap; use std::str::FromStr; +use crypto_bigint::U256; use dojo_types::primitive::Primitive; use dojo_types::schema::Ty; use dojo_world::contracts::naming; +use schema::SchemaError; use serde::{Deserialize, Serialize}; use starknet::core::types::{ ContractStorageDiffItem, Felt, FromStrError, StateDiff, StateUpdate, StorageEntry, @@ -16,6 +18,48 @@ use crate::proto::{self}; pub mod schema; +#[derive(Debug, Serialize, Deserialize, PartialEq, Hash, Eq, Clone)] +pub struct Token { + pub contract_address: Felt, + pub name: String, + pub symbol: String, + pub decimals: u8, + pub metadata: String, +} + +impl TryFrom for Token { + type Error = SchemaError; + fn try_from(value: proto::types::Token) -> Result { + Ok(Self { + contract_address: Felt::from_str(&value.contract_address)?, + name: value.name, + symbol: value.symbol, + decimals: value.decimals as u8, + metadata: value.metadata, + }) + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Hash, Eq, Clone)] +pub struct TokenBalance { + pub balance: U256, + pub account_address: Felt, + pub contract_address: Felt, + pub token_id: String, +} + +impl TryFrom for TokenBalance { + type Error = SchemaError; + fn try_from(value: proto::types::TokenBalance) -> Result { + Ok(Self { + balance: U256::from_be_hex(&value.balance), + account_address: Felt::from_str(&value.account_address)?, + contract_address: Felt::from_str(&value.contract_address)?, + token_id: value.token_id, + }) + } +} + #[derive(Debug, Serialize, Deserialize, PartialEq, Hash, Eq, Clone)] pub struct IndexerUpdate { pub head: i64, From 9aa02f29f586dc8fb31c768d6188e7bf115e1b26 Mon Sep 17 00:00:00 2001 From: Nasr Date: Tue, 19 Nov 2024 23:13:04 +0700 Subject: [PATCH 11/11] chore --- crates/torii/grpc/src/server/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/torii/grpc/src/server/mod.rs b/crates/torii/grpc/src/server/mod.rs index 23284c16d2..a0dee77df9 100644 --- a/crates/torii/grpc/src/server/mod.rs +++ b/crates/torii/grpc/src/server/mod.rs @@ -96,7 +96,7 @@ impl From for proto::types::Token { name: value.name, symbol: value.symbol, decimals: value.decimals as u32, - metadata: serde_json::to_string(&value.metadata).unwrap(), + metadata: value.metadata, } } }