Conversation
|
@greptile review the PR according to the CONTRIBUTION.md |
Greptile SummaryThis PR implements a new "Active Options Positions" feature that displays users' active options contracts with their token holdings, expiry times, and current BTC price. The implementation adds comprehensive data aggregation logic that queries option/grantor tokens, checks tokens locked in offers, validates contract collateral, and filters for active contracts where other parties hold positions. Key changes:
One potential division-by-zero issue was flagged in Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[run_positions] --> B[Fetch BTC Price]
A --> C[Get Option Tokens from Wallet]
A --> D[Get Grantor Tokens from Wallet]
C --> E[build_active_options_displays]
D --> E
B --> E
E --> F[fetch_active_contract_states]
F --> G[Parse Option Contracts]
G --> H[Build token_to_contract Map]
F --> I[Aggregate Token Balances]
C --> I
D --> I
F --> J[query_contract_tokens_in_offers]
H --> J
J --> K[map_offers_to_contracts]
F --> L[query_collateral_for_candidates]
I --> M[build_and_filter_contract_states]
K --> M
L --> M
M --> N{Filter: is_valid && is_active}
N -->|Yes| O[ContractState]
N -->|No| P[Discard]
O --> Q[Sort by Expiry]
Q --> R[Map to ActiveOptionsDisplay]
R --> S[display_active_options_table]
Last reviewed commit: 7a54d11 |
| /// Query all option tokens locked in option-offer contracts for multiple asset IDs | ||
| async fn query_all_option_tokens_in_offers( | ||
| wallet: &crate::wallet::Wallet, |
There was a problem hiding this comment.
Incorrect offer token accounting
query_all_option_tokens_in_offers is described/used as summing “option tokens locked in option-offer contracts”, but option-offer contracts lock collateral/premium (and later settlement), not option tokens. In this function you filter and sum using OptionOfferArguments::get_collateral_asset_id() and UtxoFilter::asset_id(collateral_id) (positions.rs:237-248), so option_tokens_in_offers is actually collateral-in-offers keyed by the collateral asset id. Downstream, build_maker_positions treats that map as “unsold option tokens” (option_tokens_in_offers.get(&option_asset_id) at positions.rs:371-372), so Maker “sold of total” will be wrong (typically under/over-counting depending on assets).
Also appears at positions.rs:213-274 and positions.rs:367-383.
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/cli-client/src/cli/positions.rs
Line: 213:215
Comment:
**Incorrect offer token accounting**
`query_all_option_tokens_in_offers` is described/used as summing “option tokens locked in option-offer contracts”, but option-offer contracts lock *collateral/premium* (and later settlement), not option tokens. In this function you filter and sum using `OptionOfferArguments::get_collateral_asset_id()` and `UtxoFilter::asset_id(collateral_id)` (positions.rs:237-248), so `option_tokens_in_offers` is actually *collateral-in-offers* keyed by the collateral asset id. Downstream, `build_maker_positions` treats that map as “unsold option tokens” (`option_tokens_in_offers.get(&option_asset_id)` at positions.rs:371-372), so Maker “sold of total” will be wrong (typically under/over-counting depending on assets).
Also appears at positions.rs:213-274 and positions.rs:367-383.
How can I resolve this? If you propose a fix, please make it concise.e8d39c9 to
3370cb2
Compare
|
@greptile review the PR according to the CONTRIBUTION.md |
3370cb2 to
9e7fdd6
Compare
|
@greptile review the PR according to the CONTRIBUTION.md |
| let (option_balances, grantor_balances, tokens_in_offers) = tokio::join!( | ||
| async { aggregate_token_balances(option_tokens) }, | ||
| async { aggregate_token_balances(grantor_tokens) }, | ||
| query_option_tokens_in_offers(wallet, &option_asset_ids, network) | ||
| ); |
There was a problem hiding this comment.
Unnecessary async wrapping of sync functions
aggregate_token_balances is a synchronous, CPU-bound function. Wrapping it in async { ... } and passing it to tokio::join! provides no concurrency benefit — the async block completes immediately on first poll. Only query_option_tokens_in_offers is genuinely async here.
Consider either calling the sync functions directly before the async work, or adding a comment explaining the intent:
| let (option_balances, grantor_balances, tokens_in_offers) = tokio::join!( | |
| async { aggregate_token_balances(option_tokens) }, | |
| async { aggregate_token_balances(grantor_tokens) }, | |
| query_option_tokens_in_offers(wallet, &option_asset_ids, network) | |
| ); | |
| let option_balances = aggregate_token_balances(option_tokens); | |
| let grantor_balances = aggregate_token_balances(grantor_tokens); | |
| let tokens_in_offers = query_option_tokens_in_offers(wallet, &option_asset_ids, network).await; |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/cli-client/src/cli/positions.rs
Line: 453-457
Comment:
**Unnecessary async wrapping of sync functions**
`aggregate_token_balances` is a synchronous, CPU-bound function. Wrapping it in `async { ... }` and passing it to `tokio::join!` provides no concurrency benefit — the `async` block completes immediately on first poll. Only `query_option_tokens_in_offers` is genuinely async here.
Consider either calling the sync functions directly before the async work, or adding a comment explaining the intent:
```suggestion
let option_balances = aggregate_token_balances(option_tokens);
let grantor_balances = aggregate_token_balances(grantor_tokens);
let tokens_in_offers = query_option_tokens_in_offers(wallet, &option_asset_ids, network).await;
```
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.9e7fdd6 to
56cdd41
Compare
|
@greptile review the PR according to the CONTRIBUTION.md |
| let contract_id = tpg_str.clone(); | ||
| option_asset_to_contract.insert(args.option_token(), contract_id.clone()); |
There was a problem hiding this comment.
Missing grantor token to contract mapping
Only args.option_token() is inserted into option_asset_to_contract, but grantor tokens are never mapped. This means the option_asset_ids set passed into query_option_tokens_in_offers will only contain option token asset IDs, not grantor token asset IDs. If a grantor token is ever used as collateral in an option-offer, it won't be discovered, and locked_in_offers will undercount.
Additionally, the map_offers_to_contracts function relies on this same map to resolve asset IDs back to contract IDs — any offer collateral that happens to be a grantor token would be silently dropped.
Consider also mapping the grantor token via get_grantor_token_ids() alongside the option token.
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/cli-client/src/cli/positions.rs
Line: 344:345
Comment:
**Missing grantor token to contract mapping**
Only `args.option_token()` is inserted into `option_asset_to_contract`, but grantor tokens are never mapped. This means the `option_asset_ids` set passed into `query_option_tokens_in_offers` will only contain option token asset IDs, not grantor token asset IDs. If a grantor token is ever used as collateral in an option-offer, it won't be discovered, and `locked_in_offers` will undercount.
Additionally, the `map_offers_to_contracts` function relies on this same map to resolve asset IDs back to contract IDs — any offer collateral that happens to be a grantor token would be silently dropped.
Consider also mapping the grantor token via `get_grantor_token_ids()` alongside the option token.
How can I resolve this? If you propose a fix, please make it concise.56cdd41 to
7a54d11
Compare
|
@greptile review the PR according to the CONTRIBUTION.md |
Implement a basic feature to display users’ active options positions.
Resolve: #41 (comment)
The feature currently displays the following information about active options: