Skip to content

feat: view transaction ledger query action#135

Merged
MicBun merged 6 commits intomainfrom
fetchHistory
Nov 7, 2025
Merged

feat: view transaction ledger query action#135
MicBun merged 6 commits intomainfrom
fetchHistory

Conversation

@MicBun
Copy link
Copy Markdown
Member

@MicBun MicBun commented Nov 6, 2025

Implement TransactionAction to query transaction fee events from the ledger. Enables applications to fetch transaction details including fee amounts, recipients, and distribution breakdowns.

resolves: https://github.com/trufnetwork/truf-network/issues/1331

Summary by CodeRabbit

  • New Features

    • Added support for querying transaction ledger data, enabling retrieval of transaction event details including block height, method, caller, and fee distribution information.
  • Tests

    • Added comprehensive integration tests for transaction query functionality.

Implement TransactionAction to query transaction fee events from the ledger.
Enables applications to fetch transaction details including fee amounts,
recipients, and distribution breakdowns.

resolves: trufnetwork/truf-network#1331
@MicBun MicBun requested a review from outerlook November 6, 2025 17:38
@MicBun MicBun self-assigned this Nov 6, 2025
@MicBun MicBun added the enhancement New feature or request label Nov 6, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Nov 6, 2025

Walkthrough

Introduces TransactionAction class for querying transaction ledger data via Kwil client, with new type definitions (FeeDistribution, TransactionEvent, GetTransactionEventInput), a loadTransactionAction() method on BaseTNClient, integration tests, and utility functions for transaction ID normalization.

Changes

Cohort / File(s) Summary
Transaction Action Core
src/client/client.ts, src/contracts-api/transactionAction.ts
Adds loadTransactionAction() method to BaseTNClient; introduces TransactionAction class with getTransactionEvent() and fromClient() factory, featuring comprehensive validation for transaction data including fee_amount, fee_distributions parsing, and block_height normalization
Type Definitions
src/types/transaction.ts
Defines three new interfaces: FeeDistribution (recipient/amount pair), TransactionEvent (txId, blockHeight, method, caller, feeAmount, feeRecipient, metadata, feeDistributions array), and GetTransactionEventInput (txId parameter)
Integration Tests & Utilities
tests/integration/transactionAction.test.ts, tests/integration/utils.ts
Adds new integration test suite covering non-existent transactions, tx ID validation, transaction fetching, and fee querying; introduces normalizeTransactionId() utility for 0x-prefix handling
Test & Documentation Updates
tests/integration/attestation.test.ts, src/types/attestation.ts
Disables attestation integration tests with skip modifier and updates fee values to '50000000000000000000'; adds JSDoc clarification for maxFee parameter accepting number, string, or bigint

Sequence Diagram

sequenceDiagram
    actor User
    participant Client as BaseTNClient
    participant TxAction as TransactionAction
    participant Backend as Kwil Backend

    User->>Client: loadTransactionAction()
    Client->>TxAction: new TransactionAction(kwilClient, signer)
    TxAction-->>Client: TransactionAction instance
    Client-->>User: TransactionAction

    User->>TxAction: getTransactionEvent({txId})
    TxAction->>TxAction: validate txId (non-empty)
    TxAction->>Backend: get_transaction_event(txId)
    Backend-->>TxAction: transaction data
    TxAction->>TxAction: validate fields (method, caller, fee_amount)
    TxAction->>TxAction: parse fee_distributions (recipient:amount pairs)
    TxAction->>TxAction: validate block_height (finite, non-negative)
    TxAction->>TxAction: construct & normalize TransactionEvent
    TxAction-->>User: TransactionEvent
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • TransactionAction class logic: Substantial validation chains for fee_distributions parsing and field normalization require careful review of edge cases and error handling paths
  • Integration test coverage: Multiple scenarios and mocking patterns need verification against actual network behavior
  • Type definitions and interfaces: Generally straightforward but document relationships between feeAmount, feeRecipient, and feeDistributions that should be validated

Possibly related PRs

  • feat: data attestation actions and usage #131: Introduces AttestationAction class and loadAttestationAction() method to BaseTNClient, following the same pattern of new action classes with factory methods and backend communication.

Suggested reviewers

  • outerlook
  • williamrusdyputra

Poem

🐰 A ledger of transactions, so clean and so bright,
With fees distributed fairly, everything right,
We query and validate with careful precision,
Each block, each caller, confirmed with decision!
The Kwil network speaks, and our TransactionAction hops—
Fee history's open, the querying never stops! 🌙

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: view transaction ledger query action' accurately summarizes the main change: adding TransactionAction for querying transaction ledger data.
Linked Issues check ✅ Passed The PR implements TransactionAction with getTransactionEvent() to fetch transaction details including fee amounts, recipients, and distributions, fully addressing issue #1331's objective to provide SDK functionality for fee history/details queries.
Out of Scope Changes check ✅ Passed The PR contains minimal out-of-scope changes: JSDoc updates to attestation.ts and disabling attestation tests are peripheral to the core TransactionAction feature but related to documentation and test maintenance.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fetchHistory

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c0c0a5 and 60aa568.

📒 Files selected for processing (1)
  • src/types/attestation.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/types/attestation.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@holdex
Copy link
Copy Markdown

holdex bot commented Nov 6, 2025

Time Submission Status

Member Status Time Action Last Update
MicBun ✅ Submitted 6h Update time Nov 7, 2025, 1:59 PM
@outerlook ❌ Missing - ⚠️ Submit time -

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
tests/integration/transactionAction.test.ts (1)

70-72: Consider extracting duplicate tx hash normalization logic.

The tx hash normalization logic appears twice (lines 70-72 and lines 124-126). Consider extracting this into a helper function to improve maintainability.

// In tests/integration/utils.ts or within this test file
function normalizeTxHash(txHash: string): string {
  return txHash.startsWith("0x") ? txHash.toLowerCase() : `0x${txHash.toLowerCase()}`;
}

Then use it in the tests:

-        const normalizedTxId = txEvent.txId.toLowerCase();
-        const normalizedTxHash = txHash.startsWith("0x") ? txHash.toLowerCase() : `0x${txHash.toLowerCase()}`;
-        expect(normalizedTxId).toBe(normalizedTxHash);
+        expect(txEvent.txId.toLowerCase()).toBe(normalizeTxHash(txHash));

Also applies to: 124-126

src/contracts-api/transactionAction.ts (2)

56-103: Consider improving type safety for the backend response.

Using as any on line 56 loses all type safety. Consider defining an interface for the expected row shape to catch potential issues at development time.

interface TransactionEventRow {
  tx_id: string;
  block_height: string;
  method: string;
  caller: string;
  fee_amount: string;
  fee_recipient: string | null;
  metadata: string | null;
  fee_distributions: string | null;
}

// Then use it:
const row = result.data.result[0] as TransactionEventRow;

This provides better IDE support and makes the expected structure explicit.


48-50: Include response details in error messages for better debugging.

When the HTTP status is not 200, the error message doesn't include response body details that might help diagnose the issue.

     if (result.status !== 200) {
-      throw new Error(`Failed to get transaction event: HTTP ${result.status}`);
+      throw new Error(`Failed to get transaction event: HTTP ${result.status}${result.data ? ': ' + JSON.stringify(result.data) : ''}`);
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05730ab and 5cbde57.

📒 Files selected for processing (4)
  • src/client/client.ts (2 hunks)
  • src/contracts-api/transactionAction.ts (1 hunks)
  • src/types/transaction.ts (1 hunks)
  • tests/integration/transactionAction.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
tests/integration/transactionAction.test.ts (1)
tests/integration/utils.ts (2)
  • testWithDefaultWallet (9-11)
  • waitForTxSuccess (114-122)
src/client/client.ts (1)
src/contracts-api/transactionAction.ts (1)
  • TransactionAction (7-116)
src/contracts-api/transactionAction.ts (1)
src/types/transaction.ts (3)
  • GetTransactionEventInput (71-74)
  • TransactionEvent (38-66)
  • FeeDistribution (17-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (5)
src/client/client.ts (1)

205-214: LGTM! Consistent integration pattern.

The loadTransactionAction method follows the established pattern used by other loader methods in the class (loadAttestationAction, loadRoleManagementAction). The implementation correctly instantiates TransactionAction with the Kwil client and signer.

tests/integration/transactionAction.test.ts (1)

8-241: Excellent test coverage for the new feature.

The test suite comprehensively covers:

  • Error handling (non-existent tx, empty txId)
  • Transaction recording and retrieval for different methods
  • Tx hash format flexibility (with/without 0x prefix)
  • Transaction listing functionality
  • Field validation and structure

The TODO comment (lines 223-240) appropriately documents the limitation around testing fee-paying wallets and references the alternative Go test coverage.

src/types/transaction.ts (1)

14-74: LGTM! Well-designed type definitions.

The type definitions are well-structured with:

  • Clear, comprehensive documentation explaining field relationships
  • Proper handling of large numbers using string types for amounts
  • Appropriate use of optional fields (feeRecipient?, metadata?)
  • Detailed comments explaining when fields are undefined vs. populated

The documentation for TransactionEvent (lines 27-37) is particularly helpful in clarifying the relationship between feeAmount, feeRecipient, and feeDistributions.

src/contracts-api/transactionAction.ts (2)

16-31: LGTM! Clear documentation with practical example.

The JSDoc comment provides excellent guidance with a concrete usage example. The description clearly explains the method's purpose, parameters, return value, and error conditions.


113-115: LGTM! Useful factory method.

The fromClient static factory method provides a convenient alternative constructor pattern, consistent with similar patterns in the codebase (e.g., RoleManagement.fromClient).

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/contracts-api/transactionAction.ts (1)

56-79: Validate row.tx_id exists before using it in error messages.

If the backend returns a malformed response where tx_id is missing, subsequent error messages will display "(tx: undefined)" which is confusing. Validate that row.tx_id exists and is non-empty first.

  const row = result.data.result[0] as any;
+
+  // Validate tx_id is present before using it in error messages
+  if (!row.tx_id || typeof row.tx_id !== 'string' || row.tx_id.trim() === '') {
+    throw new Error('Missing or invalid tx_id in response');
+  }

  // Validate required fields
🧹 Nitpick comments (3)
src/contracts-api/transactionAction.ts (3)

1-1: Remove unused import.

The Types import from @trufnetwork/kwil-js is not used in this file.

-import { KwilSigner, NodeKwil, WebKwil, Types } from "@trufnetwork/kwil-js";
+import { KwilSigner, NodeKwil, WebKwil } from "@trufnetwork/kwil-js";

33-35: Consider adding format validation for transaction hash.

While the backend may handle various formats, validating that txId is a valid hex string (with optional 0x prefix) would catch errors earlier and provide better user feedback.

  async getTransactionEvent(input: GetTransactionEventInput): Promise<TransactionEvent> {
    if (!input.txId || input.txId.trim() === "") {
      throw new Error("tx_id is required");
    }
+
+    // Validate txId format (hex string with optional 0x prefix)
+    const txIdTrimmed = input.txId.trim();
+    const txIdWithoutPrefix = txIdTrimmed.startsWith('0x') ? txIdTrimmed.slice(2) : txIdTrimmed;
+    if (!/^[0-9a-fA-F]+$/.test(txIdWithoutPrefix)) {
+      throw new Error("tx_id must be a valid hex string");
+    }

81-113: Well-structured fee distribution parsing.

The parsing logic correctly handles the comma-separated format, uses indexOf to find the first colon (handling addresses that may contain colons), and thoroughly validates each component including non-negative amounts.

Optional enhancement: Consider validating that recipients are valid Ethereum addresses (0x-prefixed, 40 hex characters). Based on the type documentation, recipients should be Ethereum addresses.

// After line 94
const recipient = trimmedPart.substring(0, colonIndex).trim();
const amount = trimmedPart.substring(colonIndex + 1).trim();

// Add validation for Ethereum address format
if (!/^0x[0-9a-fA-F]{40}$/i.test(recipient)) {
  throw new Error(`Invalid recipient address format: ${recipient} (tx: ${row.tx_id})`);
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5cbde57 and db4eed2.

📒 Files selected for processing (1)
  • src/contracts-api/transactionAction.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/contracts-api/transactionAction.ts (1)
src/types/transaction.ts (3)
  • GetTransactionEventInput (71-74)
  • TransactionEvent (38-66)
  • FeeDistribution (17-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (5)
src/contracts-api/transactionAction.ts (5)

7-14: LGTM!

The class structure and constructor are well-designed. Using protected fields allows for potential extension while maintaining encapsulation.


58-79: Excellent validation implementation.

The required field validations comprehensively check type, presence, and validity. The non-negative check for fee_amount and the string conversion ensure data consistency. This addresses the previous review comments effectively.


115-119: LGTM!

Block height validation correctly ensures the value is a finite, non-negative integer.


121-131: LGTM!

The return statement correctly maps all fields to the TransactionEvent interface, using validated and normalized values. Optional fields are properly handled with undefined fallbacks.


133-142: LGTM!

The static factory method provides a clean API for creating TransactionAction instances. The documentation clearly explains its purpose.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/integration/transactionAction.test.ts (1)

27-27: Consider reducing console.log statements.

While console.log statements can be helpful for debugging integration tests, they create noise in test output. Consider removing them or using a structured logging approach that can be controlled via test configuration.

Alternatively, you could use vitest's built-in debugging capabilities or conditional logging based on environment variables:

const DEBUG = process.env.DEBUG_TESTS === 'true';
if (DEBUG) console.log(`✅ Successfully fetched deployStream transaction`);

Also applies to: 40-40, 51-51, 60-60, 81-86, 100-100, 114-114, 135-140, 167-167, 218-219

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db4eed2 and 76c81e2.

📒 Files selected for processing (2)
  • src/contracts-api/transactionAction.ts (1 hunks)
  • tests/integration/transactionAction.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/contracts-api/transactionAction.ts
🧰 Additional context used
🧬 Code graph analysis (1)
tests/integration/transactionAction.test.ts (1)
tests/integration/utils.ts (2)
  • testWithDefaultWallet (9-11)
  • waitForTxSuccess (114-122)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (2)
tests/integration/transactionAction.test.ts (2)

1-13: LGTM!

The test suite setup is well-structured. Using describe.sequential is appropriate for integration tests that interact with shared infrastructure, and the 6-minute timeout is reasonable for container-based testing.


15-241: Excellent test coverage for the TransactionAction feature!

The test suite comprehensively covers:

  • Error scenarios (non-existent transactions, empty inputs)
  • Happy paths for different transaction types (deployStream, insertRecords)
  • Edge cases (transaction hashes without 0x prefix)
  • Alternative query methods (list_transaction_fees)

The TODO comment at lines 223-241 provides valuable context about known limitations and explains why fee-paying wallet tests are deferred. The tests properly validate transaction structure, field types, and integration with the broader SDK.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
tests/integration/transactionAction.test.ts (1)

166-166: Remove type assertion to maintain type safety.

Using as any bypasses TypeScript's type checking. This was previously flagged in review comments.

🧹 Nitpick comments (1)
tests/integration/transactionAction.test.ts (1)

215-233: Document future test coverage needs.

The TODO clearly explains the testing gap for fee-paying wallets and references the underlying technical constraints. The current test coverage for fee-exempt scenarios is appropriate.

Would you like me to open a new issue to track the fee-paying wallet test coverage once the kwil-js test utilities are available?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76c81e2 and 205e923.

📒 Files selected for processing (2)
  • tests/integration/transactionAction.test.ts (1 hunks)
  • tests/integration/utils.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/integration/transactionAction.test.ts (1)
tests/integration/utils.ts (4)
  • setupTrufNetwork (177-177)
  • testWithDefaultWallet (9-11)
  • waitForTxSuccess (114-122)
  • normalizeTransactionId (172-174)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (5)
tests/integration/utils.ts (1)

167-174: LGTM! Efficient implementation that addresses past feedback.

The implementation successfully extracts the duplicated normalization logic and is more efficient than the suggested version—calling .toLowerCase() only once instead of up to three times.

tests/integration/transactionAction.test.ts (4)

15-42: LGTM! Comprehensive error handling coverage.

Both tests properly validate error paths using appropriate assertions and provide clear debugging output.


44-136: LGTM! Thorough transaction validation tests.

Both tests follow a solid pattern: execute transaction → wait for confirmation → query event → validate fields. The use of normalizeTransactionId correctly addresses the past review feedback, and the fee exemption behavior is well-documented.


138-161: LGTM! Prefix handling validated correctly.

The test confirms the API accepts transaction hashes with or without the 0x prefix and always returns normalized output.


179-211: LGTM! Comprehensive validation of transaction listing.

The test properly validates the response structure, ensures transactions are returned, and checks all expected fields. The logic for verifying transaction structure and content is thorough.

@MicBun MicBun requested a review from outerlook November 7, 2025 05:08
Signed-off-by: Michael Buntarman <michaelboentarman@gmail.com>
@MicBun MicBun merged commit e06cc91 into main Nov 7, 2025
5 of 6 checks passed
@MicBun MicBun deleted the fetchHistory branch November 7, 2025 14:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants