Skip to content

feat: view the result of attested data#141

Merged
williamrusdyputra merged 3 commits intomainfrom
parseAttested
Nov 13, 2025
Merged

feat: view the result of attested data#141
williamrusdyputra merged 3 commits intomainfrom
parseAttested

Conversation

@MicBun
Copy link
Copy Markdown
Member

@MicBun MicBun commented Nov 13, 2025

resolves: https://github.com/trufnetwork/trufscan/issues/117

Summary by CodeRabbit

  • New Features

    • Added a public utility to parse and verify attestation payloads, returning parsed fields and decoded ABI-encoded result rows, plus signature verification and validator address derivation.
  • Documentation

    • Added "Parsing Attestation Payloads" to the README and API reference; clarified that the attestation result field is ABI-encoded and documented the decoded row format and end-to-end workflow.
  • Examples

    • Updated example flow to use a fixed historical window, show parsing/verification steps, handle parse errors gracefully, and log detailed parsed results.

@MicBun MicBun self-assigned this Nov 13, 2025
@MicBun MicBun added the enhancement New feature or request label Nov 13, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Nov 13, 2025

Walkthrough

Adds binary attestation payload parsing and ABI-decoding utilities (parseAttestationPayload and related types), exposes them via public exports, implements byte-level/ABI decoders, updates the attestation example to verify and parse signed payloads, and expands README/API docs with parsing examples and a full attestation workflow.

Changes

Cohort / File(s) Summary
Documentation
README.md, docs/api-reference.md
Adds "Parsing Attestation Payloads" content and examples; documents parseAttestationPayload(payload: Uint8Array): ParsedAttestationPayload; clarifies 8th field (Result) is ABI-encoded; adds complete attestation workflow and examples.
Examples
examples/attestation/index.ts
Reworks example to use fixed historical window; adds canonical payload parsing via parseAttestationPayload; verifies signatures (sha256 + recoverAddress) to derive validator address; wraps parsing in try/catch and logs parsed fields and usage guidance.
Core utility
src/util/AttestationEncoding.ts
New decoding/parsing implementation: endian readers (readUint16LE, readUint32BE, readUint16BE), decoded interfaces (DecodedDataType, DecodedEncodedValue, DecodedRow, ParsedAttestationPayload), decoding funcs (decodeDataType, decodeEncodedValue, decodedValueToJS, decodeCanonicalQueryResult, decodeABIDatapoints), formatFixedPoint, and parseAttestationPayload; adds ethers AbiCoder and tests.
Public API exports
src/internal.ts
Exports parseAttestationPayload and types DecodedRow, ParsedAttestationPayload from ./util/AttestationEncoding.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant AttestationService
    participant Parser as parseAttestationPayload
    participant Verifier as SignatureVerifier

    Client->>AttestationService: requestAttestation(args)
    AttestationService-->>Client: canonicalPayload + signature

    Client->>Parser: parseAttestationPayload(canonicalPayload)
    Note over Parser: decode header, stream/action, args\ndecode ABI-encoded result -> rows
    Parser-->>Client: ParsedAttestationPayload

    Client->>Verifier: sha256(canonicalPayload) + signature
    Verifier->>Verifier: recoverAddress(hash, signature)
    Verifier-->>Client: validatorAddress

    Client->>Client: validate validatorAddress & use parsed rows
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25–35 minutes

  • Inspect byte-level parsing in src/util/AttestationEncoding.ts (offset arithmetic, endianness, bounds checks).
  • Verify ABI decoding and mapping to JS types (ethers AbiCoder usage, fixed-point formatting).
  • Confirm exported types/functions in src/internal.ts match docs/examples.
  • Review new example error handling and signature verification steps in examples/attestation/index.ts.

Possibly related PRs

Suggested reviewers

  • outerlook
  • williamrusdyputra

Poem

🐰
I hop through bytes and find the truth,
From hex and bits to tidy proof.
Validator found, rows neat and clear,
Attestations sing — the data's here!

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 title 'feat: view the result of attested data' directly and specifically describes the main change: enabling users to view/parse attestation payload results in a readable format.
Linked Issues check ✅ Passed The PR addresses the primary objective from issue #117: parsing and displaying attestation payload data in human-readable format with parseAttestationPayload, type definitions, documentation, and examples.
Out of Scope Changes check ✅ Passed All changes are scoped to parsing and displaying attestation payload results; no unrelated refactoring, dependency updates, or search enhancements (which were secondary objectives in issue #117) are included.
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 parseAttested

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.

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

🧹 Nitpick comments (1)
examples/attestation/index.ts (1)

17-18: Import from the public SDK surface
Now that parseAttestationPayload is part of the public API, pull it from the same entry point as NodeTNClient ("../../src"). Importing directly from ../../src/util/AttestationEncoding punches through the package boundary and will break once the build outputs land in dist/. Swap the import to import { NodeTNClient, parseAttestationPayload } from "../../src";.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f049ffe and cc5b551.

📒 Files selected for processing (5)
  • README.md (3 hunks)
  • docs/api-reference.md (1 hunks)
  • examples/attestation/index.ts (5 hunks)
  • src/internal.ts (1 hunks)
  • src/util/AttestationEncoding.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
examples/attestation/index.ts (2)
src/internal.ts (1)
  • parseAttestationPayload (26-26)
src/util/AttestationEncoding.ts (1)
  • parseAttestationPayload (520-661)
src/util/AttestationEncoding.ts (1)
src/internal.ts (3)
  • DecodedRow (30-30)
  • ParsedAttestationPayload (31-31)
  • parseAttestationPayload (26-26)
🪛 markdownlint-cli2 (0.18.1)
README.md

287-287: Hard tabs
Column: 1

(MD010, no-hard-tabs)


315-315: Hard tabs
Column: 1

(MD010, no-hard-tabs)

@holdex
Copy link
Copy Markdown

holdex bot commented Nov 13, 2025

Time Submission Status

Member Status Time Action Last Update
MicBun ✅ Submitted 8h Update time Nov 13, 2025, 12:52 PM
williamrusdyputra ✅ Submitted 10min Update time Nov 13, 2025, 12:52 PM

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 (2)
README.md (2)

277-309: Enhance code example with error handling and result structure clarity.

The example successfully demonstrates the happy path but lacks error handling. Consider adding:

  • Try-catch wrapper for signature recovery (invalid signatures)
  • Clarification on the structure of parsed.result (is it an array of rows? What's the row format?)

Consider adding a note or expanded example showing:

  1. Error handling when signature recovery fails
  2. How to inspect and iterate over parsed.result rows (per line 305's comment "result.length rows")
  3. Expected fields within each decoded row

This would provide users a complete workflow from the raw payload to actionable data.


320-320: Clarify ABI encoding details for Result field.

Line 320 updates the payload structure to indicate the Result field is "ABI-encoded, length-prefixed". This is a critical detail for correctness but lacks explanation.

Consider adding a brief inline note explaining what "ABI-encoded" means in this context (e.g., "Solidity ABI encoding" or link to relevant decoding documentation). This would help users understand why parseAttestationPayload is necessary rather than simple binary decoding.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc5b551 and c558370.

📒 Files selected for processing (1)
  • README.md (3 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
README.md

287-287: Hard tabs
Column: 1

(MD010, no-hard-tabs)


297-297: Hard tabs
Column: 1

(MD010, no-hard-tabs)


298-298: Hard tabs
Column: 1

(MD010, no-hard-tabs)


299-299: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ 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)
README.md (2)

486-486: Quick Reference entry aligns with new functionality.

Adding parseAttestationPayload(canonicalPayload) to the Quick Reference table is appropriate and follows the existing pattern. The table now correctly reflects the new public API for parsing.


277-309: Code example verified as correct — no changes needed.

All verification points confirm the README example is accurate:

  1. Payload slicing (65-byte signature): Matches the documented payload structure in src/util/AttestationEncoding.ts
  2. ParsedAttestationPayload type: Correctly exported interface with .result: DecodedRow[] property matching the example usage
  3. ethers imports: Both sha256 and recoverAddress are available as direct named exports in ethers v6.13.5 (the project's dependency)

The code example is ready as-is.

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

🧹 Nitpick comments (2)
src/util/AttestationEncoding.ts (2)

500-657: Comprehensive attestation payload parser with good error handling.

The parseAttestationPayload function correctly parses the canonical format:

  • Clear documentation of the 8-field payload structure
  • Sequential parsing with proper bounds checking
  • Descriptive error messages for each field
  • Correct use of big-endian for block height and length prefixes
  • Arguments decoded using decodeEncodedValue
  • Results decoded using decodeABIDatapoints

The data provider decoding logic (lines 556-576) handles multiple formats (raw 20-byte addresses, UTF-8 strings, hex strings) which provides good flexibility, though it's somewhat complex.

Optional refactor suggestion: The data provider decoding logic could be extracted into a helper function (e.g., decodeDataProvider(bytes: Uint8Array): string) to improve readability and testability, but this is a minor enhancement and not critical.


772-813: Good test coverage for helper functions.

The new tests verify:

  • Endianness correctness for uint16 and uint32 reads
  • Empty result and error cases for decodeCanonicalQueryResult

The parseAttestationPayload test is marked TODO with a note that examples/attestation/index.ts provides integration test coverage. While integration tests are valuable, consider adding a unit test with synthetic ABI-encoded data to improve test coverage and catch regressions earlier.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c558370 and acf508b.

📒 Files selected for processing (3)
  • README.md (3 hunks)
  • docs/api-reference.md (1 hunks)
  • src/util/AttestationEncoding.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/util/AttestationEncoding.ts (1)
src/internal.ts (3)
  • DecodedRow (30-30)
  • ParsedAttestationPayload (31-31)
  • parseAttestationPayload (26-26)
⏰ 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 (17)
README.md (4)

277-309: Excellent addition of attestation parsing documentation.

The new section clearly demonstrates the complete workflow: extracting the canonical payload, separating the signature, verifying the validator, and parsing the structured data. The example is comprehensive and well-structured.

Note: A past review flagged hard tab characters in this code block (lines 287, 297-299), but the current code appears to use consistent 2-space indentation. If the markdown linter still reports issues, ensure no hard tabs remain.


308-308: Verify API Reference link completeness.

The cross-reference to the API documentation is appropriate. Based on past reviews, ensure that the referenced section includes formal type definitions for both ParsedAttestationPayload and DecodedRow with complete field descriptions and examples.

I will verify the completeness of the API Reference documentation in my review of docs/api-reference.md.


320-320: Good clarification on ABI encoding.

Adding "ABI-encoded" to the Result field description provides important context for developers working with attestation payloads. This aligns with the implementation and the parsing examples.


486-486: LGTM - Quick reference entry is clear and helpful.

The addition to the quick reference table follows the existing format and improves discoverability of the new parsing functionality.

docs/api-reference.md (4)

750-806: Excellent comprehensive documentation for parseAttestationPayload.

The documentation is thorough and well-structured:

  • Clear function signature and parameters
  • Complete return type documentation with all fields explained
  • Comprehensive example demonstrating signature verification and parsing
  • Proper cross-reference to DecodedRow type at line 767

808-840: DecodedRow type now properly documented.

The formal type definition for DecodedRow has been added as requested in previous reviews. The documentation includes:

  • Complete interface definition
  • Field descriptions with context-specific usage
  • Concrete example with real data
  • Important constraint note (exactly two values for attestation results)

This addresses the past review concern about missing formal type documentation.


841-860: Clear documentation of ABI result format.

The Attestation Result Format section provides essential information:

  • Exact ABI encoding signature (abi.encode(uint256[], int256[]))
  • Important note about 18-decimal fixed-point representation
  • Concrete example showing the decoded structure

This helps developers understand the binary format and properly interpret the values.


861-909: Comprehensive attestation workflow documentation.

The Complete Attestation Workflow section provides an excellent end-to-end guide:

  • Five clear steps from request to data usage
  • Includes important retry logic for async signature polling
  • Demonstrates proper signature verification
  • Shows practical data access patterns

This serves as a valuable reference for developers implementing attestation verification.

src/util/AttestationEncoding.ts (9)

10-10: LGTM - Appropriate ethers import for ABI decoding.

The AbiCoder import from ethers v6 is correctly used in the decodeABIDatapoints function to decode ABI-encoded attestation results.


99-135: Well-implemented endianness-aware read helpers.

The new read functions (readUint16LE, readUint32BE, readUint16BE) correctly handle both little-endian and big-endian byte order. The use of >>> 0 ensures proper unsigned conversion, and the implementations are tested (lines 772-789).


137-173: Clean and well-documented type definitions.

The new types (DecodedDataType, DecodedEncodedValue, DecodedRow, ParsedAttestationPayload) are well-structured and properly exported. They provide clear interfaces for working with decoded attestation data and align with the API documentation.


175-218: Correct implementation of DataType decoding.

The decodeDataType function properly reverses the encoding format:

  • Version validation ensures compatibility
  • Variable-length name field is handled correctly
  • Returns both the decoded type and new offset for sequential parsing

220-269: Proper EncodedValue decoding implementation.

The decodeEncodedValue function correctly reverses the kwil-js EncodedValue.MarshalBinary() format:

  • Version validation for forward compatibility
  • Proper handling of variable-length type and data arrays
  • Sequential offset tracking for parsing multiple values

271-353: Correct value decoding with proper signed integer handling.

The decodedValueToJS and decodeSingleValue functions properly convert decoded values to JavaScript types:

  • NULL handling checks both empty arrays and null indicator bytes
  • Array iteration is correct
  • Signed integer fix: Lines 325-329 now use view.getBigInt64(0, false) for proper two's-complement signed int64 decoding, addressing the past review concern about unsigned interpretation
  • Appropriate fallbacks for unknown types

Note: The past review issue regarding signed integer decoding has been resolved by using DataView.getBigInt64().


355-423: Robust canonical query result decoder.

The decodeCanonicalQueryResult function correctly parses the canonical format:

  • Clear documentation of the binary format in comments
  • Proper bounds checking before each read operation
  • Descriptive error messages with context (row/column indices)
  • Correct sequential offset tracking through nested loops

425-470: Correct ABI datapoints decoding.

The decodeABIDatapoints function properly decodes ABI-encoded attestation results:

  • Handles empty data gracefully
  • Uses correct ABI types (uint256[], int256[])
  • Validates timestamp/value array length consistency
  • Applies 18-decimal fixed-point conversion via formatFixedPoint
  • Provides clear error messages

472-498: Well-implemented fixed-point formatter.

The formatFixedPoint function correctly converts fixed-point BigInt values to decimal strings:

  • Proper handling of negative values
  • Correct fractional part padding with leading zeros
  • Trailing zero removal for cleaner output
  • Edge case handling when fractional part is zero

@williamrusdyputra williamrusdyputra merged commit 9e8ab8b into main Nov 13, 2025
5 of 6 checks passed
@williamrusdyputra williamrusdyputra deleted the parseAttested branch November 13, 2025 12:52
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