-
Notifications
You must be signed in to change notification settings - Fork 13
Add single order take execution UI #2401
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: take-orders-v6-phase2-preflight
Are you sure you want to change the base?
Add single order take execution UI #2401
Conversation
- Add `getTakeCalldata` method to RaindexOrder for targeting specific orders - Add `estimateTakeOrder` method for calculating spend/receive estimates - Add `single.rs` module with `build_candidate_from_quote` and `execute_single_take` - Refactor TakeOrdersCalldataResult with proper wasm bindings (getters) - Add TakeOrderEstimate struct for UI preview calculations
- Add TAKE_ORDER transaction type - Add createTakeOrderTransaction to TransactionManager - Add Take Order button to OrderDetail component - Add Take button and Actions column to OrdersListTable - Add onTakeOrder callback prop to OrderDetail - Add handleTakeOrderModal prop to OrdersListTable
- Add TakeOrderModal component with pair selection, amount input, price cap - Add handleTakeOrder service for processing take order submissions - Add HandleTakeOrderModal type and handler to modal service - Integrate take order modal into orders list and detail pages - Support live quote refresh and estimate preview
- Add take orders feature to SDK capabilities - Document getTakeOrdersCalldata for auto-discovery by token pair - Document order.getTakeCalldata for targeting specific orders - Explain take order modes (BuyExact, BuyUpTo, SpendExact, SpendUpTo)
Refactor tests to use getter methods instead of direct field access following the wasm binding updates to TakeOrdersCalldataResult.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughAdds comprehensive take-order execution functionality across SDK and UI layers. Introduces SDK methods for calldata generation and order estimation, a single-order execution module with quote validation, a UI modal for interactive order taking, transaction flow integration, and extensive test coverage. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant TakeOrderModal as TakeOrderModal<br/>(UI)
participant handleTakeOrder as handleTakeOrder<br/>(Service)
participant RaindexClient as RaindexClient<br/>(SDK)
participant Single as single module<br/>(SDK)
participant TransactionMgr as TransactionManager
User->>TakeOrderModal: Open modal with order
TakeOrderModal->>RaindexClient: Load quotes for order
RaindexClient-->>TakeOrderModal: Quote data
TakeOrderModal->>User: Display quote details, inputs
User->>TakeOrderModal: Submit (quote, mode, amount, priceCap)
TakeOrderModal->>handleTakeOrder: processSubmit(quote, mode, etc.)
handleTakeOrder->>RaindexClient: order.getTakeCalldata()
RaindexClient->>Single: execute_single_take(candidate, mode, price_cap)
Single->>Single: Preflight checks (liquidity, price cap)
Single->>RaindexClient: RPC simulation call
RaindexClient-->>Single: Simulation result
Single-->>RaindexClient: TakeOrdersCalldataResult
RaindexClient-->>handleTakeOrder: Calldata result
handleTakeOrder->>TransactionMgr: createTakeOrderTransaction(calldata)
TransactionMgr->>User: Confirm transaction modal
User->>TransactionMgr: Confirm
TransactionMgr->>RaindexClient: Execute takeOrders4 call
RaindexClient-->>TransactionMgr: Transaction hash
TransactionMgr->>RaindexClient: Fetch updated order (via subgraph)
RaindexClient-->>TransactionMgr: Updated order
TransactionMgr->>User: Success toast
sequenceDiagram
participant Caller as Caller<br/>(App/Test)
participant RaindexOrder as RaindexOrder<br/>(orders.rs)
participant Single as single module
participant Estimate as estimate_take_order
participant CandidateBuilder as build_candidate_from_quote
Caller->>RaindexOrder: get_take_calldata(mode, amount, price_cap)
RaindexOrder->>RaindexOrder: Load fresh quote for order
RaindexOrder->>CandidateBuilder: build_candidate_from_quote(order, quote)
CandidateBuilder->>CandidateBuilder: Validate indices, check capacity
CandidateBuilder-->>RaindexOrder: TakeOrderCandidate (or None/Error)
RaindexOrder->>Single: execute_single_take(candidate, mode, price_cap)
Single->>Single: Preflight liquidity checks
Single->>Single: Compute target input/output from mode
Single->>Single: Build simulation config
Single->>Single: Run RPC simulation
Single-->>RaindexOrder: TakeOrdersCalldataResult
RaindexOrder-->>Caller: Result with calldata, prices, effective_price
Caller->>RaindexOrder: estimate_take_order_method(quote)
RaindexOrder->>Estimate: estimate_take_order(max_output, ratio, is_buy, amount)
Estimate->>Estimate: Compute expected_spend, expected_receive, is_partial
Estimate-->>RaindexOrder: TakeOrderEstimate
RaindexOrder-->>Caller: Estimate result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
…-execution # Conflicts: # crates/common/src/raindex_client/take_orders/result.rs
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. 🤖 Generated with Claude Code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@crates/common/src/raindex_client/take_orders/single_tests.rs`:
- Around line 58-133: The tests use LocalEvm via base_setup_test() and must run
with Tokio's multi_thread runtime to avoid stalls; update each test attribute
(e.g., #[tokio::test] on functions like
test_single_order_take_happy_path_buy_up_to and the other 15 tests in this file)
to #[tokio::test(flavor = "multi_thread")], keeping the function bodies
unchanged so LocalEvm from base_setup_test() runs on the multi-threaded flavor.
In `@crates/common/src/raindex_client/take_orders/single.rs`:
- Around line 104-187: The code currently calls find_failing_order_index (which
re-simulates) even for single-order cases; inside execute_single_take's
Err(sim_error) branch, check if the built config contains only one order (e.g.
built.config.orders.len() == 1) and if so immediately return a PreflightError
with the simulation error (no extra RPC/simulation); otherwise keep the existing
logic that calls find_failing_order_index(...) and formats the error based on
whether it returns Some or None.
In `@packages/ui-components/src/lib/components/tables/OrdersListTable.svelte`:
- Around line 223-234: The icon-only menu Button (the Button component rendering
DotsVerticalOutline with id/data-testid like `order-menu-${item.id}`) lacks an
accessible name; add one by providing an aria-label (e.g., aria-label={`Open
order actions for ${item.id}`}) or an aria-labelledby that points to a visually
hidden text element inside the same component so screen readers get context;
ensure the attribute is added to the Button element that has on:click and the
DotsVerticalOutline so the button is announced meaningfully.
In `@packages/webapp/src/lib/components/TakeOrderModal.svelte`:
- Around line 43-70: In loadQuotes, ensure stale errors are cleared and
selectedPairIndex is clamped after a successful refresh: when order.getQuotes()
succeeds (after filtering into quotes) reset errorMessage to an empty string and
then adjust selectedPairIndex so it is within [0, quotes.length-1] (or set to
-1/0 if you represent "none selected") so it cannot point past the end when
quotes shrank; do this in the success path right after assigning quotes (and
before returning) so both normal loads and isRefresh loads clear errors and
clamp selection.
| #[tokio::test] | ||
| async fn test_single_order_take_happy_path_buy_up_to() { | ||
| let setup = base_setup_test().await; | ||
| let sg_server = MockServer::start_async().await; | ||
|
|
||
| let vault_id = B256::from(U256::from(1u64)); | ||
| fund_standard_two_token_vault(&setup, vault_id).await; | ||
|
|
||
| let vault1 = create_vault(vault_id, &setup, &setup.token1_sg); | ||
| let vault2 = create_vault(vault_id, &setup, &setup.token2_sg); | ||
|
|
||
| let dotrain = create_dotrain_config_with_params(&setup, "100", "2"); | ||
| let (order_bytes, order_hash) = deploy_order(&setup, dotrain).await; | ||
|
|
||
| let order_json = create_sg_order_json( | ||
| &setup, | ||
| &order_bytes, | ||
| order_hash, | ||
| vec![vault1.clone(), vault2.clone()], | ||
| vec![vault1.clone(), vault2.clone()], | ||
| ); | ||
|
|
||
| sg_server.mock(|when, then| { | ||
| when.path("/sg"); | ||
| then.status(200).json_body_obj(&json!({ | ||
| "data": { | ||
| "orders": [order_json] | ||
| } | ||
| })); | ||
| }); | ||
|
|
||
| let yaml = get_minimal_yaml_for_chain( | ||
| 123, | ||
| &setup.local_evm.url().to_string(), | ||
| &sg_server.url("/sg"), | ||
| &setup.orderbook.to_string(), | ||
| ); | ||
|
|
||
| let client = RaindexClient::new(vec![yaml], None).unwrap(); | ||
|
|
||
| let order = client | ||
| .get_order_by_hash(&OrderbookIdentifier::new(123, setup.orderbook), order_hash) | ||
| .await | ||
| .unwrap(); | ||
|
|
||
| let taker = setup.local_evm.signer_wallets[1].default_signer().address(); | ||
| fund_and_approve_taker( | ||
| &setup, | ||
| setup.token1, | ||
| taker, | ||
| setup.orderbook, | ||
| U256::from(10).pow(U256::from(22)), | ||
| ) | ||
| .await; | ||
|
|
||
| let max_output = Float::parse("100".to_string()).unwrap(); | ||
| let ratio = Float::parse("2".to_string()).unwrap(); | ||
| let max_input = max_output.mul(ratio).unwrap(); | ||
| let quote = make_quote( | ||
| 0, | ||
| 1, | ||
| Some(make_quote_value(max_output, max_input, ratio)), | ||
| true, | ||
| ); | ||
|
|
||
| let candidate = build_candidate_from_quote(&order, "e) | ||
| .unwrap() | ||
| .expect("Should build candidate from quote"); | ||
|
|
||
| let mode = parse_buy_up_to("50"); | ||
| let price_cap = Float::parse(high_price_cap()).unwrap(); | ||
| let rpc_urls = vec![url::Url::parse(&setup.local_evm.url()).unwrap()]; | ||
|
|
||
| let result = execute_single_take(candidate, mode, price_cap, taker, &rpc_urls, None) | ||
| .await | ||
| .expect("Should succeed with BuyUpTo mode"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Check the actual test decorator at lines 58-133
cat -n crates/common/src/raindex_client/take_orders/single_tests.rs | sed -n '50,135p'Repository: rainlanguage/rain.orderbook
Length of output: 3297
🏁 Script executed:
# Find base_setup_test() definition to confirm it provides LocalEvm
rg -A 10 "async fn base_setup_test" crates/common/src/raindex_client/take_orders/Repository: rainlanguage/rain.orderbook
Length of output: 53
🏁 Script executed:
# List all test functions in this file to see which ones use base_setup_test()
rg "#\[tokio::test" crates/common/src/raindex_client/take_orders/single_tests.rs -A 1Repository: rainlanguage/rain.orderbook
Length of output: 1357
🏁 Script executed:
# Search for base_setup_test definition in the entire crates/common directory
rg "fn base_setup_test" crates/common/ -A 5Repository: rainlanguage/rain.orderbook
Length of output: 53
🏁 Script executed:
# Get the full test file to see setup patterns
wc -l crates/common/src/raindex_client/take_orders/single_tests.rsRepository: rainlanguage/rain.orderbook
Length of output: 136
🏁 Script executed:
# Count which tests call base_setup_test
rg "base_setup_test()" crates/common/src/raindex_client/take_orders/single_tests.rs | wc -lRepository: rainlanguage/rain.orderbook
Length of output: 73
🏁 Script executed:
# Check imports and module structure at start of the file
head -50 crates/common/src/raindex_client/take_orders/single_tests.rsRepository: rainlanguage/rain.orderbook
Length of output: 1779
🏁 Script executed:
# Search repo-wide for base_setup_test definition
rg "fn base_setup_test" . -A 5Repository: rainlanguage/rain.orderbook
Length of output: 53
🏁 Script executed:
# Find the setup_test function in local_evm module
rg "fn setup_test" crates/common/src/test_helpers/ -A 10Repository: rainlanguage/rain.orderbook
Length of output: 142
🏁 Script executed:
# Also check if there are any multi_thread decorated tests already in the codebase for reference
rg "tokio::test.*multi_thread" crates/common/src/ -B 1 | head -20Repository: rainlanguage/rain.orderbook
Length of output: 977
🏁 Script executed:
# Find test_helpers directory
fd "test_helpers" crates/ -type dRepository: rainlanguage/rain.orderbook
Length of output: 241
🏁 Script executed:
# Also check the parent module structure
ls -la crates/common/src/ | grep -E "^d"Repository: rainlanguage/rain.orderbook
Length of output: 528
🏁 Script executed:
# Find test_helpers in the entire crates/common
find crates/common -name "test_helpers*" -o -name "local_evm*"Repository: rainlanguage/rain.orderbook
Length of output: 104
🏁 Script executed:
# Search for where setup_test or test_helpers is defined
rg "mod test_helpers" crates/common/Repository: rainlanguage/rain.orderbook
Length of output: 303
🏁 Script executed:
# Try searching in the root crates/common/src
ls -la crates/common/src/*.rs | head -20Repository: rainlanguage/rain.orderbook
Length of output: 1522
🏁 Script executed:
# Check the test_helpers.rs file for local_evm and setup_test
rg "pub mod local_evm|fn setup_test" crates/common/src/test_helpers.rs -A 5Repository: rainlanguage/rain.orderbook
Length of output: 573
🏁 Script executed:
# Get the LocalEvm structure to confirm it provides local_evm field
rg "struct LocalEvm|pub local_evm" crates/common/src/test_helpers.rs -B 2 -A 5Repository: rainlanguage/rain.orderbook
Length of output: 509
Use multi_thread tokio flavor for LocalEvm-backed tests.
All tests in this file call base_setup_test(), which provides a LocalEvm instance. They should be annotated with #[tokio::test(flavor = "multi_thread")] to avoid runtime stalls. This pattern is already established in other test files in the codebase (e.g., replays.rs, add_order.rs, unit_tests.rs).
Suggested fix (apply to all 16 tests)
-#[tokio::test]
+#[tokio::test(flavor = "multi_thread")]
async fn test_single_order_take_happy_path_buy_up_to() {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #[tokio::test] | |
| async fn test_single_order_take_happy_path_buy_up_to() { | |
| let setup = base_setup_test().await; | |
| let sg_server = MockServer::start_async().await; | |
| let vault_id = B256::from(U256::from(1u64)); | |
| fund_standard_two_token_vault(&setup, vault_id).await; | |
| let vault1 = create_vault(vault_id, &setup, &setup.token1_sg); | |
| let vault2 = create_vault(vault_id, &setup, &setup.token2_sg); | |
| let dotrain = create_dotrain_config_with_params(&setup, "100", "2"); | |
| let (order_bytes, order_hash) = deploy_order(&setup, dotrain).await; | |
| let order_json = create_sg_order_json( | |
| &setup, | |
| &order_bytes, | |
| order_hash, | |
| vec![vault1.clone(), vault2.clone()], | |
| vec![vault1.clone(), vault2.clone()], | |
| ); | |
| sg_server.mock(|when, then| { | |
| when.path("/sg"); | |
| then.status(200).json_body_obj(&json!({ | |
| "data": { | |
| "orders": [order_json] | |
| } | |
| })); | |
| }); | |
| let yaml = get_minimal_yaml_for_chain( | |
| 123, | |
| &setup.local_evm.url().to_string(), | |
| &sg_server.url("/sg"), | |
| &setup.orderbook.to_string(), | |
| ); | |
| let client = RaindexClient::new(vec![yaml], None).unwrap(); | |
| let order = client | |
| .get_order_by_hash(&OrderbookIdentifier::new(123, setup.orderbook), order_hash) | |
| .await | |
| .unwrap(); | |
| let taker = setup.local_evm.signer_wallets[1].default_signer().address(); | |
| fund_and_approve_taker( | |
| &setup, | |
| setup.token1, | |
| taker, | |
| setup.orderbook, | |
| U256::from(10).pow(U256::from(22)), | |
| ) | |
| .await; | |
| let max_output = Float::parse("100".to_string()).unwrap(); | |
| let ratio = Float::parse("2".to_string()).unwrap(); | |
| let max_input = max_output.mul(ratio).unwrap(); | |
| let quote = make_quote( | |
| 0, | |
| 1, | |
| Some(make_quote_value(max_output, max_input, ratio)), | |
| true, | |
| ); | |
| let candidate = build_candidate_from_quote(&order, "e) | |
| .unwrap() | |
| .expect("Should build candidate from quote"); | |
| let mode = parse_buy_up_to("50"); | |
| let price_cap = Float::parse(high_price_cap()).unwrap(); | |
| let rpc_urls = vec![url::Url::parse(&setup.local_evm.url()).unwrap()]; | |
| let result = execute_single_take(candidate, mode, price_cap, taker, &rpc_urls, None) | |
| .await | |
| .expect("Should succeed with BuyUpTo mode"); | |
| #[tokio::test(flavor = "multi_thread")] | |
| async fn test_single_order_take_happy_path_buy_up_to() { | |
| let setup = base_setup_test().await; | |
| let sg_server = MockServer::start_async().await; | |
| let vault_id = B256::from(U256::from(1u64)); | |
| fund_standard_two_token_vault(&setup, vault_id).await; | |
| let vault1 = create_vault(vault_id, &setup, &setup.token1_sg); | |
| let vault2 = create_vault(vault_id, &setup, &setup.token2_sg); | |
| let dotrain = create_dotrain_config_with_params(&setup, "100", "2"); | |
| let (order_bytes, order_hash) = deploy_order(&setup, dotrain).await; | |
| let order_json = create_sg_order_json( | |
| &setup, | |
| &order_bytes, | |
| order_hash, | |
| vec![vault1.clone(), vault2.clone()], | |
| vec![vault1.clone(), vault2.clone()], | |
| ); | |
| sg_server.mock(|when, then| { | |
| when.path("/sg"); | |
| then.status(200).json_body_obj(&json!({ | |
| "data": { | |
| "orders": [order_json] | |
| } | |
| })); | |
| }); | |
| let yaml = get_minimal_yaml_for_chain( | |
| 123, | |
| &setup.local_evm.url().to_string(), | |
| &sg_server.url("/sg"), | |
| &setup.orderbook.to_string(), | |
| ); | |
| let client = RaindexClient::new(vec![yaml], None).unwrap(); | |
| let order = client | |
| .get_order_by_hash(&OrderbookIdentifier::new(123, setup.orderbook), order_hash) | |
| .await | |
| .unwrap(); | |
| let taker = setup.local_evm.signer_wallets[1].default_signer().address(); | |
| fund_and_approve_taker( | |
| &setup, | |
| setup.token1, | |
| taker, | |
| setup.orderbook, | |
| U256::from(10).pow(U256::from(22)), | |
| ) | |
| .await; | |
| let max_output = Float::parse("100".to_string()).unwrap(); | |
| let ratio = Float::parse("2".to_string()).unwrap(); | |
| let max_input = max_output.mul(ratio).unwrap(); | |
| let quote = make_quote( | |
| 0, | |
| 1, | |
| Some(make_quote_value(max_output, max_input, ratio)), | |
| true, | |
| ); | |
| let candidate = build_candidate_from_quote(&order, "e) | |
| .unwrap() | |
| .expect("Should build candidate from quote"); | |
| let mode = parse_buy_up_to("50"); | |
| let price_cap = Float::parse(high_price_cap()).unwrap(); | |
| let rpc_urls = vec![url::Url::parse(&setup.local_evm.url()).unwrap()]; | |
| let result = execute_single_take(candidate, mode, price_cap, taker, &rpc_urls, None) | |
| .await | |
| .expect("Should succeed with BuyUpTo mode"); |
🤖 Prompt for AI Agents
In `@crates/common/src/raindex_client/take_orders/single_tests.rs` around lines 58
- 133, The tests use LocalEvm via base_setup_test() and must run with Tokio's
multi_thread runtime to avoid stalls; update each test attribute (e.g.,
#[tokio::test] on functions like test_single_order_take_happy_path_buy_up_to and
the other 15 tests in this file) to #[tokio::test(flavor = "multi_thread")],
keeping the function bodies unchanged so LocalEvm from base_setup_test() runs on
the multi-threaded flavor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have any issues with the testing at the moment. If we have issues, we can implement this but for now we'll leave this as it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@findolor, understood! I'll defer this suggestion. If you encounter any runtime issues with these tests in the future, the multi_thread flavor annotation is available as a potential solution.
🧠 Learnings used
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 2363
File: crates/common/src/take_orders/preflight.rs:80-107
Timestamp: 2025-12-18T08:19:55.397Z
Learning: In crates/common/src/take_orders/preflight.rs, the simulate_take_orders function intentionally returns () and discards the simulation result data because it only needs to verify that the transaction doesn't revert with the given parameters, without requiring access to output amounts or other returndata.
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 2391
File: crates/rest_api/src/main.rs:66-201
Timestamp: 2026-01-16T11:13:10.390Z
Learning: In crates/rest_api, happy-path integration tests for the /take-orders endpoint are intentionally omitted because they would require mocking blockchain and subgraph infrastructure, which is considered too complex for the value provided. The test suite focuses on error-path validation instead.
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 1903
File: crates/settings/src/yaml/orderbook.rs:371-377
Timestamp: 2025-06-17T16:21:24.384Z
Learning: In crates/settings/src/yaml/orderbook.rs tests, the user findolor considers RPC ordering in Vec<Url> assertions to be intentional and not a test brittleness issue. The ordering of RPCs in tests should be preserved as specified.
Learnt from: 0xgleb
Repo: rainlanguage/rain.orderbook PR: 1911
File: crates/common/src/raindex_client/orders.rs:720-720
Timestamp: 2025-07-21T16:34:04.947Z
Learning: In the rainlanguage/rain.orderbook codebase, user 0xgleb prefers using `.unwrap()` in test code rather than `.expect()` with descriptive messages, considering the direct unwrap approach acceptable for test contexts where failures should be fast and clear.
Learnt from: brusherru
Repo: rainlanguage/rain.orderbook PR: 2036
File: packages/orderbook/test/js_api/filters.test.ts:19-36
Timestamp: 2025-08-02T03:55:25.215Z
Learning: In the rainlanguage/rain.orderbook project's WASM tests, the pattern of chaining `.value!` calls on WASM result types (like from VaultsFilterBuilder methods) is the established and preferred approach for handling WASM results, and should not be refactored into intermediate variables as it would add unnecessary verbosity without improving the code.
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 2391
File: crates/rest_api/src/routes/take_orders.rs:75-93
Timestamp: 2026-01-16T11:17:10.568Z
Learning: In crates/rest_api, the take_orders handler uses spawn_blocking with a dedicated single-threaded Tokio runtime per request because RaindexClient contains Rc<RefCell<...>> internally which is not Send, while Rocket requires handler futures to be Send. This pattern is intentional and required to satisfy Rust's thread-safety requirements.
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 2360
File: crates/common/src/test_helpers.rs:329-367
Timestamp: 2025-12-17T13:17:58.487Z
Learning: In the rainlanguage/rain.orderbook codebase, findolor considers hardcoded values (like decimals) acceptable in test helper functions such as deposit_to_orderbook in crates/common/src/test_helpers.rs, as test infrastructure doesn't need the same level of parameterization as production code.
Learnt from: 0xgleb
Repo: rainlanguage/rain.orderbook PR: 1859
File: crates/quote/src/quote_debug.rs:472-492
Timestamp: 2025-05-20T10:20:08.206Z
Learning: In the Rain Orderbook codebase, the `#[tokio::test(flavor = "multi_thread")]` annotation is specifically needed for tests that use `LocalEvm`, not just for consistency across all async tests.
Learnt from: brusherru
Repo: rainlanguage/rain.orderbook PR: 2036
File: crates/js_api/src/filters/raindex_filter_store.rs:446-533
Timestamp: 2025-08-02T02:34:32.237Z
Learning: In the rainlanguage/rain.orderbook project's RaindexFilterStore WASM tests (crates/js_api/src/filters/raindex_filter_store.rs), brusherru decided to focus on testing only methods without side effects (that don't use web_sys) due to difficulties with mocking localStorage and window APIs in the WASM test environment. This pragmatic approach tests pure logic separately from browser integration.
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 2117
File: crates/js_api/src/gui/select_tokens.rs:421-424
Timestamp: 2025-09-02T08:04:34.729Z
Learning: User findolor in the rainlanguage/rain.orderbook codebase prefers not to change test code when tests are already passing, even if there appear to be type mismatches or potential issues. Working tests should be left alone unless there are actual errors.
Learnt from: 0xgleb
Repo: rainlanguage/rain.orderbook PR: 1911
File: crates/subgraph/src/vault_balance_changes_query.rs:133-135
Timestamp: 2025-07-23T13:03:40.669Z
Learning: User 0xgleb prefers not to make changes to test code when tests are already passing, even if the code format could be standardized differently. Working test code should be left alone unless there's a functional issue.
Learnt from: brusherru
Repo: rainlanguage/rain.orderbook PR: 2044
File: tauri-app/src/routes/orders/[chainId]-[orderbook]-[orderHash]/+page.svelte:76-78
Timestamp: 2025-07-31T19:03:56.594Z
Learning: In the rainlanguage/rain.orderbook project, when the Tauri app has issues preventing proper testing, the team prefers to defer Tauri-specific implementations to separate PRs rather than including untested code, especially for financial operations like withdrawals.
Learnt from: 0xgleb
Repo: rainlanguage/rain.orderbook PR: 1911
File: crates/common/src/erc20.rs:336-350
Timestamp: 2025-07-21T16:33:12.129Z
Learning: In the rainlanguage/rain.orderbook codebase, user 0xgleb considers both LocalEvm-based tests and mocked tests to be "unit tests" - they don't distinguish between them as "unit" vs "integration" tests based on their implementation approach.
Learnt from: brusherru
Repo: rainlanguage/rain.orderbook PR: 2044
File: crates/common/src/raindex_client/vaults_list.rs:363-423
Timestamp: 2025-07-31T19:34:11.716Z
Learning: In the rainlanguage/rain.orderbook project, for WASM-exposed functionality like VaultsList, the team prefers to keep comprehensive tests in the non-WASM environment due to the complexity of recreating objects like RaindexVaults in WASM. WASM tests focus on basic functionality and error cases since the WASM code reuses the already-tested non-WASM implementation.
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 1975
File: packages/orderbook/test/js_api/gui.test.ts:958-960
Timestamp: 2025-07-09T14:00:09.618Z
Learning: In test files for the rain.orderbook project, maintainer findolor prefers to keep hard-coded serialized state strings (like gzip/base64 blobs) rather than replacing them with semantic assertions or round-trip testing, even when the hard-coded approach may be more brittle to changes.
Learnt from: 0xgleb
Repo: rainlanguage/rain.orderbook PR: 1790
File: tauri-app/src-tauri/src/commands/vault.rs:67-67
Timestamp: 2025-05-17T15:32:28.733Z
Learning: For the PR focused on testing Tauri commands::order module, the generic type parameter R: Runtime was selectively added where needed for the PR scope, applying the changes primarily to order.rs and related files while leaving other modules like vault.rs for potential future refactoring.
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 1907
File: packages/orderbook/test/common/test.test.ts:75-77
Timestamp: 2025-06-04T10:21:01.388Z
Learning: The DotrainOrder.create API in packages/orderbook/test/common/test.test.ts is internal and not used directly in consumer applications, so API changes here don't require external breaking change documentation.
Learnt from: CR
Repo: rainlanguage/rain.orderbook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T16:50:31.752Z
Learning: Applies to crates/integration_tests/**/*.rs : Rust: write tests using `cargo test`; integration tests live in `crates/integration_tests`. Prefer `insta` snapshots and `proptest` where helpful
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 2000
File: crates/common/src/raindex_client/vaults.rs:183-183
Timestamp: 2025-07-16T10:40:05.717Z
Learning: In the rainlanguage/rain.orderbook codebase, user findolor considers breaking changes from Option<U256> to U256 for required fields like decimals in RaindexVaultToken to be acceptable and safe, even when they affect multiple usage sites across the codebase.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:26:31.566Z
Learning: For PR `#1884` and future PRs in rainlanguage/rain.orderbook repository, provide PR size reports in a separate comment with ONLY the exact format "TOTAL=number\nADDITIONS=number\nDELETIONS=number", without any additional text or explanation. Reports should exclude irrelevant files such as lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, cargo.lock).
Learnt from: hardingjam
Repo: rainlanguage/rain.orderbook PR: 1512
File: packages/ui-components/src/__tests__/OrderDetail.test.ts:125-143
Timestamp: 2025-04-08T12:56:03.272Z
Learning: The OrderDetail component in the Rain orderbook UI doesn't currently have error handling tests, but issue `#1605` has been created to address this in the future.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T22:14:22.646Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, I must consistently report the PR size after EVERY new commit in the exact format "TOTAL=number\nADDITIONS=number\nDELETIONS=number" without any additional text or formatting blocks. The report must exclude lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, cargo.lock) and can be included either as part of the review or as a separate comment.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T22:14:22.646Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, I must consistently report the PR size after EVERY new commit in the exact format "TOTAL=number\nADDITIONS=number\nDELETIONS=number" without any formatting blocks. The report must exclude lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, cargo.lock) and can be included either as part of the review or as a separate comment.
| pub async fn execute_single_take( | ||
| candidate: TakeOrderCandidate, | ||
| mode: ParsedTakeOrdersMode, | ||
| price_cap: Float, | ||
| taker: Address, | ||
| rpc_urls: &[Url], | ||
| block_number: Option<u64>, | ||
| ) -> Result<TakeOrdersCalldataResult, RaindexError> { | ||
| let zero = Float::zero()?; | ||
|
|
||
| if candidate.ratio.gt(price_cap)? { | ||
| return Err(RaindexError::NoLiquidity); | ||
| } | ||
|
|
||
| let target = mode.target_amount(); | ||
| let is_buy_mode = mode.is_buy_mode(); | ||
|
|
||
| let (output, input) = if is_buy_mode { | ||
| let output = if candidate.max_output.lte(target)? { | ||
| candidate.max_output | ||
| } else { | ||
| target | ||
| }; | ||
| let input = output.mul(candidate.ratio)?; | ||
| (output, input) | ||
| } else { | ||
| let max_input = candidate.max_output.mul(candidate.ratio)?; | ||
| let input = if max_input.lte(target)? { | ||
| max_input | ||
| } else { | ||
| target | ||
| }; | ||
| let output = if candidate.ratio.eq(zero)? { | ||
| candidate.max_output | ||
| } else { | ||
| input.div(candidate.ratio)? | ||
| }; | ||
| (output, input) | ||
| }; | ||
|
|
||
| if output.lte(zero)? { | ||
| return Err(RaindexError::NoLiquidity); | ||
| } | ||
|
|
||
| let sim = SimulationResult { | ||
| legs: vec![SelectedTakeOrderLeg { | ||
| candidate: candidate.clone(), | ||
| input, | ||
| output, | ||
| }], | ||
| total_input: input, | ||
| total_output: output, | ||
| }; | ||
|
|
||
| let built = build_take_orders_config_from_simulation(sim, mode, price_cap)? | ||
| .ok_or(RaindexError::NoLiquidity)?; | ||
|
|
||
| let provider = | ||
| mk_read_provider(rpc_urls).map_err(|e| RaindexError::PreflightError(e.to_string()))?; | ||
|
|
||
| let orderbook = candidate.orderbook; | ||
|
|
||
| let sim_result = | ||
| simulate_take_orders(&provider, orderbook, taker, &built.config, block_number).await; | ||
|
|
||
| match sim_result { | ||
| Ok(()) => build_calldata_result(orderbook, built, mode, price_cap), | ||
| Err(sim_error) => { | ||
| if let Some(_failing_idx) = | ||
| find_failing_order_index(&provider, orderbook, taker, &built.config, block_number) | ||
| .await | ||
| { | ||
| Err(RaindexError::PreflightError(format!( | ||
| "Order failed simulation: {}", | ||
| sim_error | ||
| ))) | ||
| } else { | ||
| Err(RaindexError::PreflightError(format!( | ||
| "Simulation failed: {}", | ||
| sim_error | ||
| ))) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Avoid double simulation for single‑order preflight failures.
find_failing_order_index re‑simulates even when only one order is present. Short‑circuiting avoids an extra RPC call.
♻️ Proposed refactor
match sim_result {
Ok(()) => build_calldata_result(orderbook, built, mode, price_cap),
Err(sim_error) => {
- if let Some(_failing_idx) =
- find_failing_order_index(&provider, orderbook, taker, &built.config, block_number)
- .await
- {
- Err(RaindexError::PreflightError(format!(
- "Order failed simulation: {}",
- sim_error
- )))
- } else {
- Err(RaindexError::PreflightError(format!(
- "Simulation failed: {}",
- sim_error
- )))
- }
+ if built.config.orders.len() == 1 {
+ Err(RaindexError::PreflightError(format!(
+ "Order failed simulation: {}",
+ sim_error
+ )))
+ } else if let Some(_failing_idx) = find_failing_order_index(
+ &provider,
+ orderbook,
+ taker,
+ &built.config,
+ block_number,
+ )
+ .await
+ {
+ Err(RaindexError::PreflightError(format!(
+ "Order failed simulation: {}",
+ sim_error
+ )))
+ } else {
+ Err(RaindexError::PreflightError(format!(
+ "Simulation failed: {}",
+ sim_error
+ )))
+ }
}
}🤖 Prompt for AI Agents
In `@crates/common/src/raindex_client/take_orders/single.rs` around lines 104 -
187, The code currently calls find_failing_order_index (which re-simulates) even
for single-order cases; inside execute_single_take's Err(sim_error) branch,
check if the built config contains only one order (e.g.
built.config.orders.len() == 1) and if so immediately return a PreflightError
with the simulation error (no extra RPC/simulation); otherwise keep the existing
logic that calls find_failing_order_index(...) and formats the error based on
whether it returns Some or None.
| <Button | ||
| color="alternative" | ||
| outline={false} | ||
| data-testid={`order-menu-${item.id}`} | ||
| id={`order-menu-${item.id}`} | ||
| class="border-none px-2" | ||
| on:click={(e) => { | ||
| e.stopPropagation(); | ||
| }} | ||
| > | ||
| <DotsVerticalOutline class="dark:text-white" /> | ||
| </Button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an accessible label to the icon-only actions menu button.
Line 223-234: Screen readers will announce only “button” without context. Provide an accessible name.
Suggested fix
- <Button
+ <Button
color="alternative"
outline={false}
data-testid={`order-menu-${item.id}`}
id={`order-menu-${item.id}`}
class="border-none px-2"
+ aria-label="Order actions"
+ title="Order actions"
on:click={(e) => {
e.stopPropagation();
}}
>🤖 Prompt for AI Agents
In `@packages/ui-components/src/lib/components/tables/OrdersListTable.svelte`
around lines 223 - 234, The icon-only menu Button (the Button component
rendering DotsVerticalOutline with id/data-testid like `order-menu-${item.id}`)
lacks an accessible name; add one by providing an aria-label (e.g.,
aria-label={`Open order actions for ${item.id}`}) or an aria-labelledby that
points to a visually hidden text element inside the same component so screen
readers get context; ensure the attribute is added to the Button element that
has on:click and the DotsVerticalOutline so the button is announced
meaningfully.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not needed at the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@findolor, understood! I'll skip this for now.
🧠 Learnings used
Learnt from: hardingjam
Repo: rainlanguage/rain.orderbook PR: 1512
File: packages/ui-components/src/__tests__/OrderDetail.test.ts:0-0
Timestamp: 2025-04-09T09:28:05.097Z
Learning: The OrderDetail component has been refactored to use an `onRemove` callback approach instead of the previous `handleOrderRemoveModal` pattern for order removal functionality, as part of PR `#1512`.
Learnt from: hardyjosh
Repo: rainlanguage/rain.orderbook PR: 2035
File: packages/ui-components/src/lib/components/tables/OrdersListTable.svelte:167-174
Timestamp: 2025-07-26T06:56:28.207Z
Learning: In OrdersListTable.svelte, maintainer hardyjosh considers keyed each-blocks unnecessary for item.inputs and item.outputs arrays because the entire query result updates at once during refresh, making DOM diffing optimizations negligible when the whole dataset is replaced rather than individual items being modified.
Learnt from: brusherru
Repo: rainlanguage/rain.orderbook PR: 2083
File: packages/ui-components/src/lib/components/tables/VaultsListTable.svelte:205-205
Timestamp: 2025-08-14T14:16:34.044Z
Learning: In the VaultsListTable component, the `matchesAccount` function from the wallet provider may not properly update on wallet connect/disconnect events, making direct comparison with the reactive `$account` variable more reliable for UI visibility checks. The `matchesAccount` function needs future refactoring to handle wallet state changes properly.
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 2358
File: packages/ui-components/src/lib/components/tables/OrdersListTable.svelte:82-85
Timestamp: 2025-12-11T07:46:32.817Z
Learning: In packages/ui-components/src/lib/components/tables/OrdersListTable.svelte, the token filter intentionally sets both inputs and outputs to the same selectedTokens array (lines 82-85) to achieve OR filtering behavior. This is by design: the single UI token filter should match orders containing the selected token(s) in either inputs OR outputs, not pair-specific filtering. Even though the API supports more granular directional filtering, the UI uses the same tokens in both fields for broader matching.
Learnt from: brusherru
Repo: rainlanguage/rain.orderbook PR: 2002
File: tauri-app/src/lib/components/ModalMultipleVaultsWithdraw.svelte:20-25
Timestamp: 2025-07-24T08:16:47.393Z
Learning: In the Rain OrderBook Tauri app, modal components directly mutate the `open` prop (setting `open = false`) as a consistent pattern across the codebase. This approach is maintained for consistency even though it violates typical Svelte one-way data flow, with plans to refactor all modals together in the future rather than making isolated changes.
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 2384
File: packages/ui-components/src/lib/components/dropdown/DropdownOrderbooksFilter.svelte:95-107
Timestamp: 2026-01-07T10:38:00.196Z
Learning: In DropdownOrderbooksFilter.svelte, selectedOrderbookAddresses is a filtered view (by selected chain IDs) while the activeOrderbookAddresses store holds all user selections across all chains. The toggleOrderbook function intentionally checks selection state against the filtered view (selectedOrderbookAddresses) but modifies the full store ($activeOrderbookAddresses) to preserve selections even when chain filters change.
Learnt from: brusherru
Repo: rainlanguage/rain.orderbook PR: 1957
File: packages/ui-components/src/lib/components/tables/VaultsListTable.svelte:60-60
Timestamp: 2025-06-27T17:34:15.825Z
Learning: In the VaultsListTable.svelte component, the `activeAccounts` store is redundant in query keys when the `owners` variable (derived from `activeAccountsItems`) is already included, as `owners` is what's actually used in the query function while `activeAccounts` is just a transformed version of the same data.
Learnt from: hardingjam
Repo: rainlanguage/rain.orderbook PR: 1504
File: packages/ui-components/src/lib/components/detail/VaultDetail.svelte:85-102
Timestamp: 2025-04-08T08:53:50.707Z
Learning: For icon-only buttons in the Rain UI components, aria-labels should be added to ensure accessibility for screen reader users.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:24:53.708Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, provide a separate comment after each review with PR size statistics in the format: `TOTAL=number ADDITIONS=number DELETIONS=number`, excluding lock files like package-lock.json and cargo.lock.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T21:26:31.566Z
Learning: For PR `#1884` and future PRs in rainlanguage/rain.orderbook repository, provide PR size reports in a separate comment with ONLY the exact format "TOTAL=number\nADDITIONS=number\nDELETIONS=number", without any additional text or explanation. Reports should exclude irrelevant files such as lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, cargo.lock).
Learnt from: hardingjam
Repo: rainlanguage/rain.orderbook PR: 1512
File: packages/ui-components/src/__tests__/OrderDetail.test.ts:125-143
Timestamp: 2025-04-08T12:56:03.272Z
Learning: The OrderDetail component in the Rain orderbook UI doesn't currently have error handling tests, but issue `#1605` has been created to address this in the future.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T22:14:22.646Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, I must consistently report the PR size after EVERY new commit in the exact format "TOTAL=number\nADDITIONS=number\nDELETIONS=number" without any additional text or formatting blocks. The report must exclude lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, cargo.lock) and can be included either as part of the review or as a separate comment.
Learnt from: rouzwelt
Repo: rainlanguage/rain.orderbook PR: 0
File: :0-0
Timestamp: 2025-05-21T22:14:22.646Z
Learning: For PR `#1884` in rainlanguage/rain.orderbook, I must consistently report the PR size after EVERY new commit in the exact format "TOTAL=number\nADDITIONS=number\nDELETIONS=number" without any formatting blocks. The report must exclude lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, cargo.lock) and can be included either as part of the review or as a separate comment.
Learnt from: findolor
Repo: rainlanguage/rain.orderbook PR: 2000
File: crates/common/src/raindex_client/vaults.rs:183-183
Timestamp: 2025-07-16T10:40:05.717Z
Learning: In the rainlanguage/rain.orderbook codebase, user findolor considers breaking changes from Option<U256> to U256 for required fields like decimals in RaindexVaultToken to be acceptable and safe, even when they affect multiple usage sites across the codebase.
Learnt from: brusherru
Repo: rainlanguage/rain.orderbook PR: 2044
File: tauri-app/src/routes/orders/[chainId]-[orderbook]-[orderHash]/+page.svelte:76-78
Timestamp: 2025-07-31T19:03:56.594Z
Learning: In the rainlanguage/rain.orderbook project, when the Tauri app has issues preventing proper testing, the team prefers to defer Tauri-specific implementations to separate PRs rather than including untested code, especially for financial operations like withdrawals.
| const loadQuotes = async (isRefresh = false) => { | ||
| if (isRefresh) { | ||
| isFetchingQuotes = true; | ||
| } else { | ||
| isLoadingQuotes = true; | ||
| } | ||
|
|
||
| try { | ||
| const result = await order.getQuotes(); | ||
| if (result.error) { | ||
| if (!isRefresh) { | ||
| errorMessage = result.error.readableMsg; | ||
| } | ||
| return; | ||
| } | ||
| quotes = result.value.filter((q: RaindexOrderQuote) => q.success && q.data); | ||
| if (quotes.length === 0 && !isRefresh) { | ||
| errorMessage = 'No valid quotes available for this order'; | ||
| } | ||
| } catch (e) { | ||
| if (!isRefresh) { | ||
| errorMessage = e instanceof Error ? e.message : 'Failed to load quotes'; | ||
| } | ||
| } finally { | ||
| isLoadingQuotes = false; | ||
| isFetchingQuotes = false; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clear stale errors and clamp pair selection after quote refresh.
Line 43-70: if a refresh succeeds after an earlier error, errorMessage remains visible; and selectedPairIndex can point past quotes.length if the list shrinks. Reset/clamp on successful load.
Suggested fix
try {
const result = await order.getQuotes();
if (result.error) {
if (!isRefresh) {
errorMessage = result.error.readableMsg;
}
return;
}
quotes = result.value.filter((q: RaindexOrderQuote) => q.success && q.data);
+ if (quotes.length > 0) {
+ errorMessage = '';
+ }
+ if (selectedPairIndex >= quotes.length) {
+ selectedPairIndex = 0;
+ }
if (quotes.length === 0 && !isRefresh) {
errorMessage = 'No valid quotes available for this order';
}
} catch (e) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const loadQuotes = async (isRefresh = false) => { | |
| if (isRefresh) { | |
| isFetchingQuotes = true; | |
| } else { | |
| isLoadingQuotes = true; | |
| } | |
| try { | |
| const result = await order.getQuotes(); | |
| if (result.error) { | |
| if (!isRefresh) { | |
| errorMessage = result.error.readableMsg; | |
| } | |
| return; | |
| } | |
| quotes = result.value.filter((q: RaindexOrderQuote) => q.success && q.data); | |
| if (quotes.length === 0 && !isRefresh) { | |
| errorMessage = 'No valid quotes available for this order'; | |
| } | |
| } catch (e) { | |
| if (!isRefresh) { | |
| errorMessage = e instanceof Error ? e.message : 'Failed to load quotes'; | |
| } | |
| } finally { | |
| isLoadingQuotes = false; | |
| isFetchingQuotes = false; | |
| } | |
| }; | |
| const loadQuotes = async (isRefresh = false) => { | |
| if (isRefresh) { | |
| isFetchingQuotes = true; | |
| } else { | |
| isLoadingQuotes = true; | |
| } | |
| try { | |
| const result = await order.getQuotes(); | |
| if (result.error) { | |
| if (!isRefresh) { | |
| errorMessage = result.error.readableMsg; | |
| } | |
| return; | |
| } | |
| quotes = result.value.filter((q: RaindexOrderQuote) => q.success && q.data); | |
| if (quotes.length > 0) { | |
| errorMessage = ''; | |
| } | |
| if (selectedPairIndex >= quotes.length) { | |
| selectedPairIndex = 0; | |
| } | |
| if (quotes.length === 0 && !isRefresh) { | |
| errorMessage = 'No valid quotes available for this order'; | |
| } | |
| } catch (e) { | |
| if (!isRefresh) { | |
| errorMessage = e instanceof Error ? e.message : 'Failed to load quotes'; | |
| } | |
| } finally { | |
| isLoadingQuotes = false; | |
| isFetchingQuotes = false; | |
| } | |
| }; |
🤖 Prompt for AI Agents
In `@packages/webapp/src/lib/components/TakeOrderModal.svelte` around lines 43 -
70, In loadQuotes, ensure stale errors are cleared and selectedPairIndex is
clamped after a successful refresh: when order.getQuotes() succeeds (after
filtering into quotes) reset errorMessage to an empty string and then adjust
selectedPairIndex so it is within [0, quotes.length-1] (or set to -1/0 if you
represent "none selected") so it cannot point past the end when quotes shrank;
do this in the success path right after assigning quotes (and before returning)
so both normal loads and isRefresh loads clear errors and clamp selection.
When a single order fails simulation, skip the redundant call to find_failing_order_index since we already know the failing order is index 0. This saves an unnecessary RPC call.
- Clear errorMessage when quotes load successfully - Reset selectedPairIndex to 0 if it exceeds new quotes length - Add tests for both behaviors
Merge commit 9a3244c which updates e2e tests to use TakeOrdersCalldataResult enum pattern for approval/ready states.
Add approval flow to execute_single_take: - Check token allowance before building take order calldata - Return NeedsApproval result with approval calldata when insufficient - Update tests to use getter methods on result types - Export approval module as pub(crate) for internal use
- processSubmit now checks isNeedsApproval and shows approval modal - Returns boolean to indicate whether to close TakeOrderModal - Modal stays open after successful approval with toast message - User clicks "Take Order" again to proceed with fresh quotes - Update tests with approval flow mocks and assertions - Wire up addToast in order pages
Chained PRs
Motivation
See issues:
Users need the ability to execute take orders against specific individual orders they've selected, rather than only using the auto-discovery mechanism that finds orders by token pair. This enables precise control over which order to trade against.
Solution
Adds single order take execution capability across the SDK, UI components, and webapp:
Rust SDK (
crates/common):getTakeCalldatamethod onRaindexOrderfor targeting specific orders with fresh quote fetchingestimateTakeOrdermethod for calculating spend/receive estimates for UI previewTakeOrderEstimatestruct exposing expected spend, receive, and partial fill indicatorTakeOrdersCalldataResultwith proper wasm gettersUI Components (
packages/ui-components):TAKE_ORDERtransaction typecreateTakeOrderTransactionin TransactionManagerWebapp (
packages/webapp):TakeOrderModalwith pair selection, direction (buy/sell), amount input, price caphandleTakeOrderservice for processing submissionsChecks
By submitting this for review, I'm confirming I've done the following:
fix #2396
Summary by CodeRabbit
Release Notes
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.