Skip to content

Conversation

@findolor
Copy link
Collaborator

@findolor findolor commented Jan 21, 2026

Chained PRs

Motivation

See issues:

Phase 3 of the vaultless orders implementation. When orders have vaultless: true on outputs, funds flow directly from the user's wallet instead of orderbook vaults. This requires the GUI to handle approvals differently (approve orderbook to spend wallet tokens) and skip deposit generation for vaultless outputs.

Solution

GUI Order Operations (order_operations.rs):

  • generateApprovalCalldatas() now generates approvals for vaultless outputs with U256::MAX (infinite approval) by default
  • Added optional vaultlessApprovalAmounts parameter (Map<tokenKey, amount>) for custom approval amounts per token
  • generateDepositCalldatas() skips vaultless outputs since they don't use vaults
  • getDeploymentTransactionArgs() accepts the same optional vaultless approval amounts parameter

Error Handling (mod.rs):

  • Added InvalidU256 error variant for invalid approval amount strings
  • Added vaultless test fixtures (vaultless-deployment, mixed-vault-deployment)

Tests:

  • Rust unit tests for vaultless approval generation (default infinite, custom amounts, already approved)
  • Rust unit tests for deposit calldata skipping vaultless outputs
  • TypeScript tests mirroring the Rust test coverage

Documentation:

  • Updated SDK README with vaultless mode explanation
  • Documented the optional vaultlessApprovalAmounts parameter

Checks

By submitting this for review, I'm confirming I've done the following:

  • made this PR as small as possible
  • unit-tested any new functionality
  • linked any relevant issues or PRs
  • included screenshots (if this involves a front-end change)

fix #2405

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced vaultless mode to draw funds directly from user wallets via token approvals
    • Added support for customizable approval amounts per token (defaults to maximum allowance)
    • Enhanced error handling for invalid numeric values
  • Documentation

    • Updated guide with vaultless mode functionality and approval customization examples

✏️ Tip: You can customize this high-level summary in your review settings.

@findolor findolor self-assigned this Jan 21, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 21, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This PR implements vaultless order operations support in the GUI layer. Changes include: adding GuiError::InvalidU256 variant, introducing VaultlessApprovalAmounts type for per-token approval amounts, updating generate_approval_calldatas() and get_deployment_transaction_args() to handle vaultless outputs with optional custom approval amounts, modifying deposit handling to skip vaultless tokens, and extending tests and documentation to cover vaultless workflows.

Changes

Cohort / File(s) Summary
Error Handling
crates/js_api/src/gui/mod.rs
Added GuiError::InvalidU256(String) variant and corresponding message formatting in to_readable_msg() for invalid U256 value handling.
Vaultless Approval Logic
crates/js_api/src/gui/order_operations.rs
Introduced VaultlessApprovalAmounts public struct for per-token approval amount overrides; expanded generate_approval_calldatas() to discover vaultless outputs, compute approval amounts (defaulting to max uint256), check current allowances, and emit calldata only when approval != current; updated get_deployment_transaction_args() signature to accept vaultless approval amounts; refactored deposit generation to skip vaultless inputs; introduced graceful error handling for invalid vault_id during deposit conversion.
State Serialization Tests
crates/js_api/src/gui/state_management.rs
Removed hard-coded SERIALIZED_STATE constant and refactored tests to generate serialized state at runtime instead of comparing against predefined blobs; updated test_new_from_state and test_new_from_state_invalid_dotrain to dynamically construct and serialize state.
Documentation
packages/orderbook/README.md
Added vaultless mode description to feature list; included code comments documenting vaultless approval defaults (infinite approval) and optional custom amount overrides via vaultlessApprovals map.
Test Coverage
packages/orderbook/test/js_api/gui.test.ts
Added comprehensive vaultless test suite covering approval calldata generation (infinite and custom amounts), allowance checks, vault ID retrieval, deposits skipping for vaultless outputs, and multi-deployment scenarios with vaultless configurations integrated into existing GUI test blocks.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI/Client
    participant GUI as DotrainOrderGui
    participant ERC20 as ERC20 Contract
    participant OB as Orderbook

    UI->>GUI: get_deployment_transaction_args(owner, vaultless_approval_amounts)
    
    GUI->>GUI: Parse deployment & discover vaultless outputs
    
    alt Vaultless outputs found
        loop For each vaultless token
            GUI->>GUI: Resolve approval amount (custom or max uint256)
            GUI->>ERC20: allowance(owner, orderbook)
            ERC20-->>GUI: current_allowance
            
            alt current_allowance != target_amount
                GUI->>GUI: Generate approval calldata
            else
                GUI->>GUI: Skip approval (already set)
            end
        end
    end
    
    GUI->>GUI: Skip deposit generation for vaultless inputs
    GUI-->>UI: Return deployment args with approval calldatas
    UI->>OB: Execute approval transactions
    UI->>OB: Execute order deployment
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Suggested labels

rust, js/wasm, test

Suggested reviewers

  • 0xgleb
  • hardyjosh
🚥 Pre-merge checks | ✅ 5
✅ 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 'Add vaultless support to GUI order operations' accurately and concisely summarizes the main change—implementing vaultless order handling in the GUI layer.
Linked Issues check ✅ Passed The PR fully implements all primary objectives from issue #2405: updated generate_deposit_calldatas() to skip vaultless outputs, updated generate_approval_calldatas() with optional vaultlessApprovalAmounts parameter, defaults to U256::MAX for infinite approval, and includes comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly aligned with vaultless phase 3 implementation: new error variant InvalidU256, new VaultlessApprovalAmounts type, updated calldata generation logic, modified tests to use dynamic state, and documentation updates—all within scope of handling vaultless orders in GUI operations.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@findolor findolor requested review from 0xgleb and hardyjosh January 21, 2026 07:54
@findolor
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 21, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

1 similar comment
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 21, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/js_api/src/gui/order_operations.rs (1)

343-435: Only skip deposit approval for tokens that are exclusively vaultless, not when they appear in both vaulted and vaultless outputs.

A token used in both a vaulted output and a vaultless output requires deposit approval for the vaulted portion. The current check skips approval whenever a token appears in any vaultless output, causing insufficient allowance for vaulted deposits. Track vaulted addresses separately and only skip when a token is exclusively vaultless.

🔧 Suggested fix (track vaulted vs vaultless addresses)
-use std::{collections::HashMap, str::FromStr, sync::Arc};
+use std::{collections::{HashMap, HashSet}, str::FromStr, sync::Arc};

@@
-        let vaultless_addresses: Vec<Address> = vaultless_outputs
+        let vaultless_addresses: Vec<Address> = vaultless_outputs
             .iter()
             .filter_map(|output| output.token.as_ref().map(|t| t.address))
             .collect();
+        let vaulted_addresses: HashSet<Address> = deployment
+            .deployment
+            .order
+            .outputs
+            .iter()
+            .filter(|output| output.vaultless != Some(true))
+            .filter_map(|output| output.token.as_ref().map(|t| t.address))
+            .collect();

@@
-            if vaultless_addresses.contains(token_address) {
+            if vaultless_addresses.contains(token_address)
+                && !vaulted_addresses.contains(token_address)
+            {
                 continue;
             }
🤖 Fix all issues with AI agents
In `@packages/orderbook/README.md`:
- Around line 471-473: Add a commented example showing how to pass the optional
Map parameter to getDeploymentTransactionArgs (e.g., a Map of token keys to
custom approval amounts) so readers can see vaultless approval usage; create a
variable whose name matches the actual parameter name in the API (use the
verified parameter name for getDeploymentTransactionArgs) and show calling
getDeploymentTransactionArgs('0xOwner', <thatVariable>) with a brief inline
comment explaining that omitting or passing undefined yields infinite approval
(max uint256).
- Around line 463-466: Update the README example to use the correct parameter
name expected by the API: replace the local variable vaultlessApprovals with
vaultlessApprovalAmounts and pass vaultlessApprovalAmounts into
gui.generateApprovalCalldatas (referencing the example variables and the
generateApprovalCalldatas function) so the doc matches the implementation.

Comment on lines 463 to 466
// For vaultless outputs, you can optionally specify custom approval amounts per token.
// By default, vaultless outputs use infinite approval (max uint256).
// const vaultlessApprovals = new Map([['output-token', '1000000000000000000']]);
// const approvalCalldatasResult = await gui.generateApprovalCalldatas('0xOwner', vaultlessApprovals);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for the vaultless approval parameter in the implementation
rg -n "vaultless.*approval" --type rust crates/js_api/src/gui/order_operations.rs -C 3

Repository: rainlanguage/rain.orderbook

Length of output: 2808


Update parameter name in documentation example.

The example uses vaultlessApprovals, but the actual API parameter is vaultlessApprovalAmounts. Update the variable name to match the implementation:

Show diff
// For vaultless outputs, you can optionally specify custom approval amounts per token.
// By default, vaultless outputs use infinite approval (max uint256).
-// const vaultlessApprovals = new Map([['output-token', '1000000000000000000']]);
-// const approvalCalldatasResult = await gui.generateApprovalCalldatas('0xOwner', vaultlessApprovals);
+// const vaultlessApprovalAmounts = new Map([['output-token', '1000000000000000000']]);
+// const approvalCalldatasResult = await gui.generateApprovalCalldatas('0xOwner', vaultlessApprovalAmounts);
🤖 Prompt for AI Agents
In `@packages/orderbook/README.md` around lines 463 - 466, Update the README
example to use the correct parameter name expected by the API: replace the local
variable vaultlessApprovals with vaultlessApprovalAmounts and pass
vaultlessApprovalAmounts into gui.generateApprovalCalldatas (referencing the
example variables and the generateApprovalCalldatas function) so the doc matches
the implementation.

Comment on lines 471 to 475
// For vaultless outputs, pass an optional Map of token keys to custom approval amounts.
// Omit or pass undefined for infinite approval (max uint256) on vaultless tokens.
const deploymentArgsResult = await gui.getDeploymentTransactionArgs('0xOwner');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add example showing the optional parameter usage.

While the comment mentions passing an optional Map to getDeploymentTransactionArgs, no example demonstrates this. Consider adding a commented example similar to lines 463-466:

 // For vaultless outputs, pass an optional Map of token keys to custom approval amounts.
 // Omit or pass undefined for infinite approval (max uint256) on vaultless tokens.
+// const vaultlessApprovals = new Map([['output-token', '1000000000000000000']]);
+// const deploymentArgsResult = await gui.getDeploymentTransactionArgs('0xOwner', vaultlessApprovals);
 const deploymentArgsResult = await gui.getDeploymentTransactionArgs('0xOwner');

Note: Ensure the variable name matches the verified parameter name from the API.

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

Suggested change
// For vaultless outputs, pass an optional Map of token keys to custom approval amounts.
// Omit or pass undefined for infinite approval (max uint256) on vaultless tokens.
const deploymentArgsResult = await gui.getDeploymentTransactionArgs('0xOwner');
// For vaultless outputs, pass an optional Map of token keys to custom approval amounts.
// Omit or pass undefined for infinite approval (max uint256) on vaultless tokens.
// const vaultlessApprovals = new Map([['output-token', '1000000000000000000']]);
// const deploymentArgsResult = await gui.getDeploymentTransactionArgs('0xOwner', vaultlessApprovals);
const deploymentArgsResult = await gui.getDeploymentTransactionArgs('0xOwner');
🤖 Prompt for AI Agents
In `@packages/orderbook/README.md` around lines 471 - 473, Add a commented example
showing how to pass the optional Map parameter to getDeploymentTransactionArgs
(e.g., a Map of token keys to custom approval amounts) so readers can see
vaultless approval usage; create a variable whose name matches the actual
parameter name in the API (use the verified parameter name for
getDeploymentTransactionArgs) and show calling
getDeploymentTransactionArgs('0xOwner', <thatVariable>) with a brief inline
comment explaining that omitting or passing undefined yields infinite approval
(max uint256).

@findolor findolor force-pushed the 2025-01-20-vaultless-phase-2-sdk-validation branch from 08b0b59 to 995b510 Compare January 22, 2026 12:59
@findolor findolor force-pushed the 2026-01-20-vaultless-phase-3-gui-order-operations branch from e3e1098 to 309a484 Compare January 22, 2026 13:02
@findolor findolor force-pushed the 2025-01-20-vaultless-phase-2-sdk-validation branch from 995b510 to e742b2f Compare January 22, 2026 13:54
@findolor findolor force-pushed the 2026-01-20-vaultless-phase-3-gui-order-operations branch from 309a484 to 9b8a03d Compare January 22, 2026 13:54
- generateApprovalCalldatas() generates approvals for vaultless outputs
- accepts optional vaultlessApprovalAmounts param for custom amounts
- defaults to U256::MAX (infinite approval) for vaultless tokens
- generateDepositCalldatas() skips vaultless outputs
- add InvalidU256 error variant for invalid approval amounts
- add vaultless test fixtures to mod.rs
Tests now generate state dynamically instead of comparing against
a hardcoded SERIALIZED_STATE constant, making them more robust
to changes in the serialization format.
- test infinite approval for vaultless outputs
- test custom approval amounts via vaultlessApprovalAmounts param
- test skipping approval when already at max
- test skipping deposits for vaultless outputs
- test getVaultIds returns undefined for vaultless tokens
- add vaultless mode to "How It Works" section
- document optional vaultlessApprovalAmounts parameter
- use < instead of != for allowance check to avoid unnecessary approvals
- fix vaultlessApprovals -> vaultlessApprovalAmounts in README example
- add example for getDeploymentTransactionArgs optional parameter
Compare U256 values directly instead of converting allowance to Float.
This fixes LossyConversionToFloat error when allowance is U256::MAX or
any value too large for Float's 224-bit coefficient. Also changes logic
to only approve when allowance < deposit amount (not when unequal).
@findolor findolor force-pushed the 2026-01-20-vaultless-phase-3-gui-order-operations branch from 9b8a03d to 99d1d11 Compare January 22, 2026 14:03
- Rename and fix test that incorrectly expected approval when allowance > deposit
- Add test for allowance = 0 case (should generate approval)
- Add test for allowance = deposit case (should skip approval)
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.

2 participants