Skip to content
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
259140e
Update server.rs
saa938 Aug 19, 2025
a113185
Update types.rs
saa938 Aug 19, 2025
424f38c
Update json_rpc_client.rs
saa938 Aug 19, 2025
3402246
Merge pull request #3 from saa938/test
saa938 Aug 19, 2025
d40784c
Update server.rs
saa938 Aug 19, 2025
9d14ac2
Update types.rs
saa938 Aug 19, 2025
c70d084
Update openrpc.json
saa938 Aug 19, 2025
32bae7c
Update openrpc.json
saa938 Aug 19, 2025
6c10300
Update types.rs
saa938 Aug 19, 2025
60ad255
Update openrpc.json
saa938 Aug 19, 2025
9adfbc6
Update openrpc.json
saa938 Aug 19, 2025
8b65616
Update applications/tari_indexer/openrpc.json
saa938 Aug 19, 2025
5d0bfbe
Update json_rpc_client.rs
saa938 Aug 19, 2025
8bbdcd4
Update openrpc.json
saa938 Aug 19, 2025
3f6eb9f
Update applications/tari_indexer/openrpc.json
saa938 Aug 19, 2025
0ad9823
Update applications/tari_indexer/openrpc.json
saa938 Aug 19, 2025
0ab232a
Update applications/tari_indexer/openrpc.json
saa938 Aug 19, 2025
3e34430
Update openrpc.json
saa938 Aug 19, 2025
17a88b5
Update applications/tari_indexer/src/json_rpc/server.rs
saa938 Aug 26, 2025
a96e257
Update openrpc.json
saa938 Aug 26, 2025
5e84834
Update openrpc.json
saa938 Aug 26, 2025
d25c9a7
Update types.rs
saa938 Aug 26, 2025
d2a77f8
Update openrpc.json
saa938 Aug 26, 2025
0935711
Update applications/tari_indexer/openrpc.json
saa938 Aug 26, 2025
98ca256
Update clients/tari_indexer_client/src/types.rs
saa938 Aug 26, 2025
9b0c541
Update Cargo.toml
saa938 Aug 26, 2025
5101a4d
Update types.rs
saa938 Aug 26, 2025
928f0da
Update store_factory.rs
saa938 Aug 26, 2025
6dae149
Update handlers.rs
saa938 Aug 26, 2025
03926c4
Update applications/tari_indexer/openrpc.json
saa938 Aug 26, 2025
78c712d
Update openrpc.json
saa938 Aug 26, 2025
12d26c6
Update handlers.rs
saa938 Aug 26, 2025
ab67002
Update applications/tari_indexer/src/json_rpc/handlers.rs
saa938 Aug 26, 2025
0e9ef5a
Update applications/tari_indexer/src/json_rpc/handlers.rs
saa938 Aug 26, 2025
5fbc61b
Update applications/tari_indexer/src/json_rpc/handlers.rs
saa938 Aug 27, 2025
fa5f556
Merge branch 'development' into saa938/development
sdbondi Sep 18, 2025
1ebd3de
impleemnt get substates
sdbondi Sep 18, 2025
f6d8455
sneak in nft transfer use ootle address
sdbondi Sep 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions applications/tari_indexer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ serde = { workspace = true, features = ["default", "derive"] }
serde_json = { workspace = true }
serde_with = { workspace = true, features = ["indexmap"] }
thiserror = { workspace = true }
time = { workspace = true, features = ["serde"] }
tokio = { workspace = true, features = [
"default",
"macros",
Expand Down
31 changes: 30 additions & 1 deletion applications/tari_indexer/src/json_rpc/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ use tari_indexer_client::types::{
GetNonFungiblesResponse,
GetSubstateRequest,
GetSubstateResponse,
GetSubstatesRequest,
GetSubstatesResponse,
GetTemplateDefinitionRequest,
GetTemplateDefinitionResponse,
GetTransactionResultRequest,
Expand Down Expand Up @@ -377,6 +379,29 @@ impl JsonRpcHandlers {
}
}

pub async fn get_substates(&self, value: JsonRpcExtractor) -> JrpcResult {
let answer_id = value.get_answer_id();
let req: GetSubstatesRequest = value.parse_params()?;

const MAX_REQUESTS: usize = 20;

let GetSubstatesRequest { requests } = req;

if requests.len() > MAX_REQUESTS {
return Err(Self::invalid_params(
answer_id,
format!("Cannot request more than {MAX_REQUESTS} substates at once"),
));
}

let substates = self.substate_manager.get_substates(requests.as_slice()).map_err(|e| {
warn!(target: LOG_TARGET, "Error getting substate: {}", e);
Self::internal_error(answer_id, format!("Error getting substate: {}", e))
})?;

Ok(JsonRpcResponse::success(answer_id, GetSubstatesResponse { substates }))
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

pub async fn inspect_substate(&self, value: JsonRpcExtractor) -> JrpcResult {
let answer_id = value.get_answer_id();
let request: InspectSubstateRequest = value.parse_params()?;
Expand Down Expand Up @@ -791,7 +816,7 @@ impl JsonRpcHandlers {

let transactions = self
.transaction_manager
.list_recent_transactions(req.last_id, limit as usize)
.list_recent_transactions(None, limit as usize)
.map_err(|e| Self::internal_error(answer_id, e))?;

let resp = ListRecentTransactionsResponse { transactions };
Expand Down Expand Up @@ -820,6 +845,10 @@ impl JsonRpcHandlers {
Self::error_response(answer_id, JsonRpcErrorReason::ApplicationError(404), details)
}

fn invalid_params<T: Display>(answer_id: i64, details: T) -> JsonRpcResponse {
Self::error_response(answer_id, JsonRpcErrorReason::InvalidParams, details)
}

fn internal_error<T: Display>(answer_id: i64, error: T) -> JsonRpcResponse {
error!(target: LOG_TARGET, "Internal error: {}", error);
Self::error_response(answer_id, JsonRpcErrorReason::InternalError, error)
Expand Down
1 change: 1 addition & 0 deletions applications/tari_indexer/src/json_rpc/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ async fn handler(Extension(handlers): Extension<Arc<JsonRpcHandlers>>, value: Js
// Substates
"list_substates" => handlers.list_substates(value).await,
"get_substate" => handlers.get_substate(value).await,
"get_substates" => handlers.get_substates(value).await,
"inspect_substate" => handlers.inspect_substate(value).await,
"get_non_fungibles" => handlers.get_non_fungibles(value).await,
"get_utxo_updates" => handlers.get_utxo_updates(value).await,
Expand Down
18 changes: 13 additions & 5 deletions applications/tari_indexer/src/storage_sqlite/models/substate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@

use std::convert::TryFrom;

use tari_ootle_storage::time::PrimitiveDateTime;
use tari_ootle_storage::{time::PrimitiveDateTime, StorageError};

use crate::{
storage_sqlite::{models::substate::SubstateRecord as SubstateRow, schema::substates},
storage_sqlite::{
models::substate::SubstateRecord as SubstateRow,
schema::substates,
serialization::deserialize_json,
},
substate_manager::SubstateResponse,
};

Expand All @@ -45,13 +49,17 @@ pub struct SubstateRecord {
}

impl TryFrom<SubstateRecord> for SubstateResponse {
type Error = anyhow::Error;
type Error = StorageError;

fn try_from(row: SubstateRow) -> Result<Self, Self::Error> {
Ok(SubstateResponse {
address: row.address.parse()?,
address: row.address.parse().map_err(|e| StorageError::DecodingError {
operation: "TryFrom<SubstateRecord> for SubstateResponse",
item: "Substate",
details: format!("Invalid substate address {}: {}", row.address, e),
})?,
version: row.version as u32,
substate: serde_json::from_str(&row.data)?,
substate: deserialize_json(&row.data)?,
})
}
}
Expand Down
29 changes: 24 additions & 5 deletions applications/tari_indexer/src/storage_sqlite/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@ use tari_template_lib::{
};
use tari_transaction::{Transaction, TransactionId};

use crate::storage_sqlite::{
models,
models::{EventRecord, KeyValue, ScannedBlockId, SubstateRecord},
serialization::{deserialize_hex_try_from, deserialize_json, serialize_hex},
IndexerStoreReadTransaction,
use crate::{
storage_sqlite::{
models,
models::{EventRecord, KeyValue, ScannedBlockId, SubstateRecord},
serialization::{deserialize_hex_try_from, deserialize_json, serialize_hex},
IndexerStoreReadTransaction,
},
substate_manager::SubstateResponse,
};

const LOG_TARGET: &str = "tari::indexer::storage_sqlite::reader";
Expand Down Expand Up @@ -140,6 +143,22 @@ impl IndexerStoreReadTransaction for SqliteStoreReadTransaction<'_> {
})
}

fn get_substates(&mut self, ids: &[SubstateId]) -> Result<Vec<SubstateResponse>, StorageError> {
use crate::storage_sqlite::schema::substates;

let str_ids = ids.iter().map(|id| id.to_string());

let rows = substates::table
.select(substates::all_columns)
.filter(substates::address.eq_any(str_ids))
.get_results::<SubstateRecord>(self.connection())
.map_err(|e| StorageError::QueryError {
reason: format!("get_substate: {}", e),
})?;

rows.into_iter().map(TryInto::try_into).collect()
}

fn get_non_fungible_count(&mut self, resource_address: String) -> Result<i64, StorageError> {
use crate::storage_sqlite::schema::non_fungible_indexes;

Expand Down
13 changes: 9 additions & 4 deletions applications/tari_indexer/src/storage_sqlite/store_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ use tari_template_lib::{
};
use tari_transaction::{Transaction, TransactionId};

use crate::storage_sqlite::{
models::{EventRecord, KeyValue, NewScannedBlockId, NewSubstate, SubstateRecord, UtxoUpdateRecord},
reader::SqliteStoreReadTransaction,
writer::SqliteStoreWriteTransaction,
use crate::{
storage_sqlite::{
models::{EventRecord, KeyValue, NewScannedBlockId, NewSubstate, SubstateRecord, UtxoUpdateRecord},
reader::SqliteStoreReadTransaction,
writer::SqliteStoreWriteTransaction,
},
substate_manager::SubstateResponse,
};

const LOG_TARGET: &str = "tari::indexer::storage_sqlite";
Expand Down Expand Up @@ -134,6 +137,8 @@ pub trait IndexerStoreReadTransaction {
address: &SubstateId,
version: Option<u32>,
) -> Result<Option<SubstateRecord>, StorageError>;

fn get_substates(&mut self, ids: &[SubstateId]) -> Result<Vec<SubstateResponse>, StorageError>;
fn get_non_fungible_count(&mut self, resource_address: String) -> Result<i64, StorageError>;
fn get_non_fungibles_by_resource_address(
&mut self,
Expand Down
13 changes: 11 additions & 2 deletions applications/tari_indexer/src/substate_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::convert::TryInto;
use std::{collections::HashMap, convert::TryInto};

use serde::{Deserialize, Serialize};
use tari_common_types::types::FixedHash;
use tari_engine_types::{
substate::{SubstateId, SubstateValue},
substate::{Substate, SubstateId, SubstateValue},
Utxo,
UtxoId,
};
Expand Down Expand Up @@ -160,6 +160,15 @@ impl SubstateManager {
}
}

pub fn get_substates(&self, substates: &[SubstateId]) -> Result<HashMap<SubstateId, Substate>, anyhow::Error> {
let mut tx = self.substate_store.create_read_tx()?;
let substates = tx.get_substates(substates)?;
Ok(substates
.into_iter()
.map(|rec| (rec.address, Substate::new(rec.version, rec.substate)))
.collect())
}

async fn get_substate_from_db(
&self,
substate_address: &SubstateId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,14 @@ function Resources() {
}
if (nftData) {
console.log(nftData);
let { image_url, name } = nftData;
const nftSubstateId = { NonFungible: nft.address };
let address = substateIdToString(nftSubstateId).split("_", 4);
const { image_url, name } = nftData;
const nftId = nft.address.id;
const key = Object.keys(nftId)[0];
const address = `${key}_${nftId[key as keyof typeof nftId]}`;
nfts.push({
Comment on lines +90 to 93

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use canonical address formatter; avoid Object.keys-based derivation

Relying on the “first key” of nft.address.id is brittle and can yield non-canonical or [object Object] values. Use the bindings’ formatter for a stable, canonical string.

-          const { image_url, name } = nftData;
-          const nftId = nft.address.id;
-          const key = Object.keys(nftId)[0];
-          const address = `${key}_${nftId[key as keyof typeof nftId]}`;
+          const { image_url, name } = nftData;
+          const address = substateIdToString(nft.address);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const nftId = nft.address.id;
const key = Object.keys(nftId)[0];
const address = `${key}_${nftId[key as keyof typeof nftId]}`;
nfts.push({
const { image_url, name } = nftData;
const address = substateIdToString(nft.address);
nfts.push({
🤖 Prompt for AI Agents
In applications/tari_indexer/web_ui/src/routes/VN/Components/Resources.tsx
around lines 90 to 93, replace the brittle Object.keys-based derivation of
address with the bindings' canonical address formatter: remove the
Object.keys/first-key logic and call the provided formatter on the address
object (for example use the bindings' format function or the address object's
toString/canonical method) to produce a stable canonical string, then use that
string for the address variable before pushing into nfts.

img: image_url,
title: name,
address: `${address[2]}_${address[3]}`,
address,
version: nft.version,
});
}
Expand Down Expand Up @@ -125,9 +126,9 @@ function Resources() {

{nfts.length > 0 && (
<ImageList cols={4} gap={8}>
{nfts.map((item) =>
{nfts.map((item, i) =>
item.img ? (
<ImageListItem key={item.address}>
<ImageListItem key={i}>
<img
src={`${item.img}?size=248&fit=fill&auto=format`}
srcSet={`${item.img}?size=248&fit=fill&auto=format&dpr=2 4x`}
Expand All @@ -145,7 +146,7 @@ function Resources() {
/>
</ImageListItem>
) : (
<ImageListItem key={item.address}>
<ImageListItem key={i}>
<ImageListItemBar
title={item.title}
subtitle={
Expand All @@ -156,7 +157,7 @@ function Resources() {
position="below"
/>
</ImageListItem>
)
),
)}
</ImageList>
)}
Expand Down
30 changes: 14 additions & 16 deletions applications/tari_walletd/src/handlers/substates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use tari_wallet_daemon_client::{
SubstatesGetResponse,
SubstatesListRequest,
SubstatesListResponse,
WalletSubstateRecord,
WalletSubstateInfo,
},
};

Expand Down Expand Up @@ -43,14 +43,14 @@ pub async fn handle_get(
}

Ok(SubstatesGetResponse {
record: record.map(|record| WalletSubstateRecord {
local_record: record.map(|record| WalletSubstateInfo {
version: record.substate_id.version(),
substate_id: record.substate_id.into_substate_id(),
parent_id: record.parent_address,
module_name: record.module_name,
template_address: record.template_address,
}),
substate: substate.map(|s| Substate::new(s.version, s.substate)),
substate_from_remote: substate.map(|s| Substate::new(s.version, s.substate)),
})
}

Expand All @@ -61,21 +61,19 @@ pub async fn handle_list(
) -> Result<SubstatesListResponse, anyhow::Error> {
let sdk = context.wallet_sdk().clone();
context.check_auth(token, &[JrpcPermission::SubstatesRead])?;
let substates = sdk.substate_api().list_substates(
req.filter_by_type,
req.filter_by_template.as_ref(),
req.limit,
req.offset,
)?;

let result = sdk
.get_network_interface()
.list_substates(req.filter_by_template, req.filter_by_type, req.limit, req.offset)
.await?;

let substates = result
.substates
let substates = substates
.into_iter()
// TODO: should also add the "timestamp" and "type" fields from the indexer list items?
.map(|s| WalletSubstateRecord {
substate_id: s.substate_id,
// TODO: should we remove the "parent_id" field from the wallet API? is it really needed somewhere?
parent_id: None,
version: s.version,
.map(|s| WalletSubstateInfo {
version: s.substate_id.version(),
substate_id: s.substate_id.into_substate_id(),
parent_id: s.parent_address,
template_address: s.template_address,
module_name: s.module_name,
})
Expand Down
2 changes: 1 addition & 1 deletion applications/tari_walletd/src/jrpc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ async fn handler(
},
Some(("stealth_utxos", method)) =>
{
#[allow(clippy::match_single_binding)]
#[allow(clippy::collapsible_match)]
match method {
"list" => call_handler(context, value, token, stealth_utxos::handle_list).await,
_ => Ok(value.method_not_found(&value.method)),
Expand Down
Loading
Loading