Skip to content

feat: read any wallet's order-book positions and collateral#125

Merged
MicBun merged 2 commits into
mainfrom
feat/portfolio-by-wallet
Jun 23, 2026
Merged

feat: read any wallet's order-book positions and collateral#125
MicBun merged 2 commits into
mainfrom
feat/portfolio-by-wallet

Conversation

@MicBun

@MicBun MicBun commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

resolves: https://github.com/truflation/website/issues/4171

What

Read a wallet's order-book portfolio by address from Python, plus a working demonstration in the MAA lifecycle example:

  • TNClient.get_positions_by_wallet(wallet_address) — holdings + open orders
  • TNClient.get_collateral_by_wallet(wallet_address, bridge) — total locked collateral on a bridge

Why

get_user_positions / get_user_collateral read the signer (@caller), so they cannot read a wallet you do not sign for — e.g. an owner, or a delegated market-maker bot, watching an agent wallet (MAA) whose positions live under the MAA's participant id, not the signer's. These wrap the new node action and sdk-go methods.

How

  • gopy bindings (GetPositionsByWallet / GetCollateralByWallet) forwarding to sdk-go, plus thin TNClient wrappers that JSON-parse the result and reuse the existing UserPosition / UserCollateral types.
  • Re-pins sdk-go to the merged commit that adds the methods (go.mod / go.sum); kwil-db is unchanged.

Example

examples/maa_lifecycle_example now:

  • loads config from a gitignored .env (zero-dependency loader; real env vars still win), with a committed .env.example
  • adds step (h): reads the agent wallet's positions/collateral by address
  • uses a fresh salt per run so the smoke test is re-runnable (MAA_SALT pins it)

Testing

  • tests/test_portfolio_by_wallet.py — pure unit tests (monkeypatched binding) for argument forwarding, JSON parsing, and empty handling. All pass.
  • Verified live: the example's step (h) runs against testnet and both getters return cleanly (migration 051 applied), proving the path end-to-end.

Depends on (merged)

Context

Summary by CodeRabbit

  • New Features

    • Added wallet-scoped order-book queries: get_positions_by_wallet() retrieves positions and holdings for any wallet address, while get_collateral_by_wallet() returns collateral data without requiring the wallet signer.
  • Documentation

    • Updated lifecycle example to use .env file configuration and added documentation for new wallet address-based portfolio queries.
  • Tests

    • Added unit tests covering wallet-scoped portfolio retrieval methods.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@MicBun, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 25 minutes and 7 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses rolling per-developer review limits. Reviews become available again as older review attempts age out of the rolling limit window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4787befc-ff9d-4054-940a-01d4ba6d981d

📥 Commits

Reviewing files that changed from the base of the PR and between c61d9f5 and e88d669.

📒 Files selected for processing (1)
  • examples/maa_lifecycle_example/main.py
📝 Walkthrough

Walkthrough

Two new wallet-parameterized query functions—GetPositionsByWallet and GetCollateralByWallet—are added to the Go bindings and exposed as Python TNClient methods. The MAA lifecycle example gains a _load_dotenv() helper, a .env.example template, and a new lifecycle step exercising these queries.

Changes

Wallet-parameterized portfolio queries

Layer / File(s) Summary
Go bindings and dependency
bindings/bindings.go, go.mod
GetPositionsByWallet and GetCollateralByWallet are added to the Go bindings, each loading the order book and calling the corresponding wallet-scoped method, serializing results to JSON; go.mod updates the sdk-go pseudo-version.
Python client wrappers and unit tests
src/trufnetwork_sdk_py/client.py, tests/test_portfolio_by_wallet.py
TNClient.get_positions_by_wallet and TNClient.get_collateral_by_wallet call the Go bindings and parse JSON, returning [] or zeroed UserCollateral on empty responses; unit tests monkeypatch bindings to verify argument forwarding, parsing, and empty-string defaults.
MAA example: dotenv config and new portfolio step
examples/maa_lifecycle_example/.env.example, examples/maa_lifecycle_example/main.py, examples/maa_lifecycle_example/README.md
Adds .env.example template and _load_dotenv() helper; expands env-var config with COLLATERAL_BRIDGE and optional MAA_SALT; changes salt to per-run fresh generation; adds lifecycle step (h) calling both new wallet query methods; README updated with new proof point and .env workflow.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Suggested labels

enhancement

Suggested reviewers

  • pr-time-tracker

Poem

🐇 Hop hop, a new trick I've found,
Two wallet queries, safe and sound!
GetPositions, GetCollateral by address—
No signer needed, just the hex!
The MAA example now loads .env with flair,
Empty returns? Zero, no despair. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main feature: adding capability to read any wallet's order-book positions and collateral by address.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/portfolio-by-wallet

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.

@holdex

holdex Bot commented Jun 23, 2026

Copy link
Copy Markdown

Time Submission Status

Member # Time Running Total Status Last Update
MicBun 3h ✅ Submitted Jun 23, 2026, 10:56 AM

Submit or update total time with:

@holdex pr submit-time 2h

Add time on top of previous submission with:

@holdex pr add-time 1h30m

See available commands to help comply with our Guidelines.

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
examples/maa_lifecycle_example/main.py (1)

56-83: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider adding sub-second precision to salt generation for improved uniqueness.

The fresh-salt-per-run approach using int(time.time()).to_bytes(8, "big") works well for most scenarios, but running the script twice within the same second will produce identical salts and collide. While this is acceptable for a smoke test, you could make it more robust with sub-second precision:

♻️ Optional improvement for salt uniqueness
-    SALT = b"MAA" + int(time.time()).to_bytes(8, "big") + b"\x00" * 21  # 3 + 8 + 21 = 32 bytes
+    # Use microsecond precision for sub-second uniqueness
+    timestamp_us = int(time.time() * 1_000_000)
+    SALT = b"MAA" + timestamp_us.to_bytes(8, "big") + b"\x00" * 21  # 3 + 8 + 21 = 32 bytes

Alternatively, use os.urandom(32) for cryptographically random salts, though timestamp-based salts are easier to reason about for debugging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/maa_lifecycle_example/main.py` around lines 56 - 83, The salt
generation using int(time.time()).to_bytes(8, "big") only captures second-level
precision, which means running the script twice within the same second will
produce identical salts and cause collisions. Improve the salt uniqueness by
modifying the timestamp-based salt generation to include sub-second precision.
Instead of using int(time.time()) which truncates to seconds, multiply
time.time() by a factor (such as 1000000 for microsecond precision) or use
time.time_ns() for nanosecond precision to ensure each run within the same
second gets a unique salt value. Verify the resulting bytes fit within the
8-byte constraint used in the SALT construction.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@examples/maa_lifecycle_example/main.py`:
- Around line 56-83: The salt generation using int(time.time()).to_bytes(8,
"big") only captures second-level precision, which means running the script
twice within the same second will produce identical salts and cause collisions.
Improve the salt uniqueness by modifying the timestamp-based salt generation to
include sub-second precision. Instead of using int(time.time()) which truncates
to seconds, multiply time.time() by a factor (such as 1000000 for microsecond
precision) or use time.time_ns() for nanosecond precision to ensure each run
within the same second gets a unique salt value. Verify the resulting bytes fit
within the 8-byte constraint used in the SALT construction.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9e6abbcc-741f-4053-b716-ad90137f066b

📥 Commits

Reviewing files that changed from the base of the PR and between 35a14a3 and c61d9f5.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (7)
  • bindings/bindings.go
  • examples/maa_lifecycle_example/.env.example
  • examples/maa_lifecycle_example/README.md
  • examples/maa_lifecycle_example/main.py
  • go.mod
  • src/trufnetwork_sdk_py/client.py
  • tests/test_portfolio_by_wallet.py

@MicBun MicBun self-assigned this Jun 23, 2026
@MicBun

MicBun commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

@holdex pr submit-time 3h

@MicBun MicBun merged commit 88183fd into main Jun 23, 2026
5 of 6 checks passed
@MicBun MicBun deleted the feat/portfolio-by-wallet branch June 23, 2026 10:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant