Skip to content

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

Merged
MicBun merged 1 commit into
mainfrom
feat/portfolio-by-wallet
Jun 23, 2026
Merged

feat: read any wallet's order-book positions and collateral#1399
MicBun merged 1 commit 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

Two address-parameterized, read-only order-book getters so a wallet's live portfolio can be read by address rather than by signer (migration 051):

  • get_positions_by_wallet($wallet_address) — holdings + open orders across all markets
  • get_collateral_by_wallet($wallet_address, $bridge) — total locked collateral on a bridge

Why

get_user_positions / get_user_collateral (038) read @caller, so they only ever return the signer's own rows. That 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 are recorded under the MAA's participant id, not the signer's. Migration 050 already did this for order-event history; these two complete the set for the live portfolio an inventory-aware market maker needs.

How

  • Bodies mirror the 038 getters exactly, except the participant is resolved from the $wallet_address argument (normalized with/without a 0x prefix, like 050) instead of @caller. The collateral computation is byte-for-byte identical to get_user_collateral apart from that resolution.
  • $bridge is a required argument (per-bridge token decimals) rather than env-defaulted, so the file references no bridge namespace literal and needs no dev/prod twin.
  • Only new PUBLIC VIEW reads over existing tables (no ALTER), so it is safe to apply against a live, settling node. Deploy with kwil-cli exec-sql --file 051… --sync rather than replaying all migrations.

Testing

tests/streams/order_book/portfolio_by_wallet_test.goTestPortfolioByWallet, 6 cases (all pass):

  • reads another wallet's positions / collateral while the reader's own portfolio stays empty (proves it is address-scoped, not @caller)
  • accepts the wallet with or without a 0x prefix
  • rejects a malformed address
  • returns empty / zero for a wallet that never traded

Context

Summary by CodeRabbit

Release Notes

  • New Features
    • Query portfolio positions by wallet address to monitor all holdings and orders across markets, supporting flexible wallet address formats (with or without 0x prefix).
    • Check locked collateral by wallet address per bridge to track capital allocation.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds SQL migration 051 introducing two public, wallet-parameterized, read-only order-book actions: get_positions_by_wallet (streams ob_positions rows with a position_type derived from price sign) and get_collateral_by_wallet (aggregates buy_orders_locked and shares_value per bridge via get_bridge_units_per_dollar). A new Go integration test suite validates all address normalization, cross-wallet read, and collateral computation behaviors.

Changes

Order-book portfolio-by-wallet getters

Layer / File(s) Summary
SQL migration: get_positions_by_wallet and get_collateral_by_wallet
internal/migrations/051-order-book-portfolio-by-wallet.sql
Migration 051 adds two public VIEW actions. get_positions_by_wallet normalizes and validates the hex wallet address, resolves the ob_participants row, returns empty when absent, and streams ob_positions rows with a position_type computed from the sign of price. get_collateral_by_wallet does the same wallet resolution, then aggregates buy_orders_locked from negative-price positions and shares_value from non-negative positions — both scaled via get_bridge_units_per_dollar($bridge) — returning those plus total_locked as their sum.
Go integration test suite
tests/streams/order_book/portfolio_by_wallet_test.go
TestPortfolioByWallet wires six sub-tests: empty positions and collateral for never-traded wallets, cross-wallet read returning a buy-order row while the reader's own caller-scoped positions remain empty, bare-hex (no 0x) address normalization, malformed address error rejection, and per-field collateral assertions (total_locked, buy_orders_locked, shares_value) for a placed buy order. Helper wrappers callGetPositionsByWallet and callGetCollateralByWallet centralize argument construction.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • trufnetwork/node#1285: The existing get_user_collateral action uses the same total_locked/buy_orders_locked/shares_value breakdown from negative vs non-negative price positions; this PR extends that pattern to wallet-parameterized, per-bridge queries.
  • trufnetwork/node#1391: Also introduces wallet-address-parameterized public read-only SQL actions that normalize the address and resolve ob_participants, directly parallel to the two new actions in this PR.
  • trufnetwork/node#1369: get_collateral_by_wallet reuses the get_bridge_units_per_dollar($bridge) collateral scaling logic introduced/adjusted in this PR.

Suggested labels

type: feat

Suggested reviewers

  • pr-time-tracker

Poem

🐇 Hop, hop — who holds what?
A wallet walks in, no signer required,
Positions revealed, collateral acquired.
Bare hex or prefixed, the rabbit won't slip,
Zero or locked, it tracks every tip.
The order book opens for all to inspect! 📖

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and accurately summarizes the main feature: introducing two new read-only wallet-parameterized getters for reading any wallet's order-book positions and collateral by address, which is the core purpose of this PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 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:18 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.

@MicBun MicBun self-assigned this Jun 23, 2026
@MicBun MicBun added the type: feat New feature or request label Jun 23, 2026
@MicBun

MicBun commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

@holdex pr submit-time 3h

@MicBun MicBun merged commit d7334d2 into main Jun 23, 2026
9 checks passed
@MicBun MicBun deleted the feat/portfolio-by-wallet branch June 23, 2026 10:18
MicBun added a commit to trufnetwork/sdk-py that referenced this pull request Jun 23, 2026
resolves: truflation/website#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)

- <trufnetwork/node#1399>
- <trufnetwork/sdk-go#195>

## Context

- <truflation/website#4121>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## 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.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feat New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant