Skip to content

PerpOB#51

Open
arturbeg wants to merge 63 commits into
mainfrom
feat/perpOB
Open

PerpOB#51
arturbeg wants to merge 63 commits into
mainfrom
feat/perpOB

Conversation

@arturbeg

@arturbeg arturbeg commented Apr 27, 2026

Copy link
Copy Markdown
Collaborator

Aligns with reya-api-specs feat/perpOB (v2.3.0) and the off-chain perpOB migration tracked in Reya-Labs/reya-off-chain-monorepo#2575. Perpetual futures move from AMM execution to the matching engine, sharing the spot order envelope.

EIP-712 signing rewritten for the new flat 13-field Order/OrderDetails typehash (signatures.py); the old ConditionalOrder envelope, composite perp nonce, personal_sign cancel hack, and inputs:bytes blob are gone. client.py collapses to a single signing path with no spot-vs-perp branching, and mass_cancel works for both market types. WebSocket channels switch to the unified executionBusts stream; sdk/open_api/ and sdk/async_api/ regenerated against the new spec.

Tests: shared lifecycle tests parametrized over [spot, perp] under tests/test_orderbook/; deliberate-bust scenarios in test_spot/ deleted in favour of unified bust tests there. AMM-only tests (test_perps/test_dynamic_pricing.py) deleted; tests that need maker/taker fixtures or a sign_order rewrite (test_perps/test_limit_orders.py, test_perps/test_position_management.py, test_spot/test_api_validation.py) marked pytest.mark.skip with explicit migration TODOs.

RPC layer (sdk/reya_rpc/) intentionally untouched — on-chain settlement helpers are matching-engine territory and out of scope for this PR.

Known issues

⚠️ The version-consistency CI check is expected red on this PR. The specs submodule is pinned to commit 653d108 — the v2.3.0 schema this SDK targets — but that commit isn't tagged on Reya-Labs/specs. The pin itself is intentional and correct; only the missing tag is blocking the check. Follow-up: tag 653d108 on the specs repo (e.g. as 2.3.0) and re-run this job before final merge. Not blocking review.

Summary by CodeRabbit

  • New Features

    • Added unified executionBusts API for both spot and perp markets.
    • Added spot market summary endpoints and data models.
    • Expanded perp execution details with taker/maker breakdown and PnL fields.
  • API Updates

    • Updated order type enums: TP/SLTAKE_PROFIT/STOP_LOSS.
    • Added deadline field to order requests.
    • Updated market summary fields: removed OI and oracle metrics; added mark and throttled mid prices.
  • Version

    • Bumped to v2.3.0.

Aligns with reya-api-specs feat/perpOB (v2.3.0) and the off-chain perpOB
migration tracked in Reya-Labs/reya-off-chain-monorepo#2575. Perpetual
futures move from AMM execution to the matching engine, sharing the spot
order envelope.

EIP-712 signing rewritten for the new flat 13-field Order/OrderDetails
typehash (signatures.py); the old ConditionalOrder envelope, composite
perp nonce, personal_sign cancel hack, and inputs:bytes blob are gone.
client.py collapses to a single signing path with no spot-vs-perp
branching, and mass_cancel works for both market types. WebSocket
channels switch to the unified executionBusts stream; sdk/open_api/ and
sdk/async_api/ regenerated against the new spec.

Tests: shared lifecycle tests parametrized over [spot, perp] under
tests/test_orderbook/; deliberate-bust scenarios in test_spot/ deleted in
favour of unified bust tests there. AMM-only tests
(test_perps/test_dynamic_pricing.py) deleted; tests that need
maker/taker fixtures or a sign_order rewrite (test_perps/test_limit_orders.py,
test_perps/test_position_management.py, test_spot/test_api_validation.py)
marked pytest.mark.skip with explicit migration TODOs.

RPC layer (sdk/reya_rpc/) intentionally untouched — on-chain settlement
helpers are matching-engine territory and out of scope for this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

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.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a7b495e1-6536-40fe-8eb6-4c3db87596a7

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Updates SDK from v2.1.7.0 to v2.3.0, consolidating "SpotExecutionBust" into unified "ExecutionBust" for both spot/perp markets, replacing OrderType shorthand (TP/SL) with explicit names (TAKE_PROFIT/STOP_LOSS), introducing SpotMarketSummary endpoints, refactoring signature generation and client order logic, and reorganizing test suites with some marking for rewrite.

Changes

Cohort / File(s) Summary
Version & Metadata Updates
pyproject.toml, sdk/open_api/__init__.py, sdk/open_api/api_client.py, sdk/open_api/configuration.py, sdk/open_api/exceptions.py, sdk/open_api/rest.py, .openapi-generator/FILES, sdk/open_api/models/__init__.py, sdk/open_api/api/*.py (header updates), sdk/open_api/models/*.py (header updates in 40+ files)
Bumps package version from 2.1.7.0 to 2.3.0 and updates OpenAPI document version references across all generated code and metadata.
OrderType Enum Consolidation
sdk/async_api/order_type.py, sdk/open_api/models/order_type.py, examples/rest_api/perps/order_entry.py, tests/test_perps/test_trigger_orders.py, tests/helpers/builders/order_builder.py, tests/helpers/reya_tester/checks.py
Replaces OrderType shorthand TP/SL with explicit TAKE_PROFIT/STOP_LOSS enum values across SDK models and test code.
ExecutionBust Model Consolidation
sdk/async_api/execution_bust.py, sdk/open_api/models/execution_bust.py, sdk/open_api/models/execution_bust_list.py
Renames SpotExecutionBustExecutionBust and updates reason field description from hex-encoded to human-readable format; updates list wrapper accordingly.
Execution Bust Payload Models
sdk/async_api/market_execution_bust_update_payload.py, sdk/async_api/wallet_execution_bust_update_payload.py, sdk/open_api/api/wallet_data_api.py
Renames payload models and field types from spot-specific to unified bust handling: MarketSpotExecutionBustUpdatePayloadMarketExecutionBustUpdatePayload, WalletSpotExecutionBustUpdatePayloadWalletExecutionBustUpdatePayload, and swaps data field from List[SpotExecutionBust] to List[ExecutionBust].
ExecutionType & Execution Models
sdk/async_api/execution_type.py, sdk/async_api/perp_execution.py, sdk/open_api/models/execution_type.py, sdk/open_api/models/perp_execution.py
Adds DUST to ExecutionType enum; refactors PerpExecution to split single account_id/fee into taker_account_id/maker_account_id and corresponding fee components plus PnL tracking fields.
SpotMarketSummary Models
sdk/async_api/spot_market_summary.py, sdk/async_api/spot_market_summary_update_payload.py, sdk/async_api/spot_markets_summary_channel.py, sdk/async_api/spot_markets_summary_update_payload.py, sdk/open_api/models/spot_market_summary.py
Introduces new SpotMarketSummary model with additional_properties handling; adds payload models and channel enum for spot market summary WebSocket updates and REST endpoints.
MarketSummary Field Updates
sdk/async_api/market_summary.py, sdk/open_api/models/market_summary.py
Removes fields (long_oi_qty, short_oi_qty, funding_rate_velocity, throttled_oracle_price, throttled_pool_price) and introduces new fields (mark_price, throttled_mid_price) with updated validation and additional_properties filtering.
Market Data API Refactoring
sdk/open_api/api/market_data_api.py
Renames perp executions endpoint to execution busts; adds new spot market summary endpoints; updates return types and response mappings (+561/-43 lines).
Order Model & Request Updates
sdk/open_api/models/order.py, sdk/open_api/models/cancel_order_request.py, sdk/open_api/models/create_order_request.py, sdk/open_api/models/mass_cancel_request.py
Updates OrderType field descriptions; replaces expiresAfter with deadline in cancel/mass-cancel requests; adds required deadline field to create order request; changes symbol field from optional to required in create order request.
Order Entry & Signature Refactoring
sdk/reya_rest_api/auth/signatures.py, sdk/reya_rest_api/client.py, sdk/reya_rest_api/models/orders.py
Consolidates EIP-712 signing from separate conditional/cancel flows into unified sign_order, sign_cancel_order, sign_mass_cancel; unifies order entry for spot/perp with single OrderType/TimeInForce mapping; adds deadline, client_order_id, reduce_only parameters.
Client API Method Changes
sdk/reya_rest_api/client.py, sdk/reya_rest_api/config.py
Updates method signatures: cancel_order now requires symbol; mass_cancel accepts optional symbol; replaces get_spot_execution_busts() with unified get_execution_busts(); removes pool_account_id property.
WebSocket Execution Bust Updates
sdk/reya_websocket/resources/market.py, sdk/reya_websocket/resources/wallet.py, sdk/reya_websocket/socket.py
Renames spot-specific bust methods/classes to unified versions: spot_execution_busts()execution_busts(), MarketSpotExecutionBustsResourceMarketExecutionBustsResource; updates channel paths from /spotExecutionBusts to /executionBusts.
Test Infrastructure & Helpers
tests/helpers/reya_tester/data.py, tests/helpers/reya_tester/waiters.py, tests/helpers/reya_tester/websocket.py, tests/helpers/builders/order_builder.py
Updates test helpers to use unified ExecutionBust models/methods; extends TriggerOrderBuilder with qty, limit_px, reduce_only, client_order_id; updates market/wallet bust store naming and access patterns.
Test Suite Updates & Configuration
tests/test_orderbook/conftest.py, tests/test_orderbook/test_execution_busts.py, tests/test_orderbook/test_limit_orders.py
Adds new conftest with PerpTestConfig for parametrized spot/perp testing; adds execution busts validation tests; adds unified limit order tests supporting both market types.
Perps Test Modifications
tests/test_perps/test_limit_orders.py, tests/test_perps/test_position_management.py, tests/test_perps/test_dynamic_pricing.py, tests/test_perps/test_trigger_orders.py
Marks limit orders and position management tests with skip markers pending v2.3.0 perpOB rewrite; removes entire dynamic pricing test suite; updates trigger order tests to use new OrderType enum values.
Spot Test Removals
tests/test_spot/test_spot_execution_busts.py, tests/test_spot/test_api_validation.py
Removes comprehensive spot execution busts test suite (771 lines); marks API validation tests as legacy and skips execution.
API Documentation Updates
sdk/open_api/api/order_entry_api.py, sdk/open_api/api/reference_data_api.py, sdk/open_api/api/specs_api.py
Expands endpoint docstrings to document spot/perp support; notes conditional order handling and future SL/TP native type changes; updates version metadata.
Constants & Enums Cleanup
sdk/reya_rest_api/constants/enums.py
Removes OrdersGatewayOrderType enum (replaced by SDK-level OrderType/TimeInForce mapping).
Submodule Update
specs
Updates specs submodule commit reference.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Suggested reviewers

  • tomdevman

Poem

🐰 Hops through the code with glee
Old spot busts now unified for all to see,
TP and SL become proper names,
Markets and wallets in the same lane,
Signatures streamlined, the order flow sings—
What grand improvements this update brings! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'PerpOB' is vague and does not clearly convey the main scope of this comprehensive migration PR (v2.3.0 unified spot+perp API alignment). Expand the title to be more descriptive, e.g., 'Migrate SDK to v2.3.0 unified spot+perp API (perpOB)' or 'feat(perpOB): unify spot and perp order/execution flows'.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 82.43% which is sufficient. The required threshold is 80.00%.
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/perpOB

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

@github-actions

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 22

Caution

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

⚠️ Outside diff range comments (4)
sdk/open_api/models/create_order_response.py (1)

34-34: 🧹 Nitpick | 🔵 Trivial

Consider configuring the OpenAPI generator to enforce the 120-character line length limit.

Line 34 exceeds the 120-character guideline (~157 characters). Since this is a generated file marked "Do not edit the class manually," the line length should be addressed in the OpenAPI generator configuration rather than through manual edits. As per coding guidelines, line length of 120 characters should be enforced for code formatting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/open_api/models/create_order_response.py` at line 34, The generated line
for the field "order_id" in create_order_response.py exceeds the 120-char limit;
instead of editing this generated line, update the OpenAPI generator/template
configuration to enforce a 120-character max line length (wrap long Field
descriptions or enable line wrapping) so generated model fields like order_id:
Optional[StrictStr] = Field(..., description="...", alias="orderId") are emitted
within 120 chars; adjust the generator's mustache template or code formatter
settings used in generation so all future outputs conform to the 120-character
guideline.
sdk/open_api/models/market_definition.py (1)

40-40: ⚠️ Potential issue | 🟠 Major

Fix line length violation: __properties declaration exceeds 120-character limit.

Line 40 contains 184 characters, exceeding the 120-character limit by 64 characters. The __properties list declaration must be reformatted or split across multiple lines to comply with project standards.

Since this file is auto-generated, update the generator configuration to ensure compliance with the 120-character line length requirement for all **/*.py files before regenerating.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/open_api/models/market_definition.py` at line 40, The __properties class
variable declaration in MarketDefinition exceeds the 120-character limit; split
the list literal across multiple lines so each line is ≤120 chars (e.g., one
element per line or grouped) and then update the OpenAPI/python generator
template or its configuration that produces
sdk/open_api/models/market_definition.py so all generated **/*.py files format
__properties (and similar long lists) with line wrapping under 120 chars, then
regenerate the models to apply the fix; target symbols: __properties in the
MarketDefinition model (and the generator template that emits the class property
list).
sdk/open_api/__init__.py (1)

10-17: ⚠️ Potential issue | 🟡 Minor

Version mismatch between OpenAPI document and package version.

The OpenAPI document version was updated to 2.3.0 (line 10), but __version__ remains "2.1.7.0" (line 17). This inconsistency could cause confusion when debugging or verifying SDK compatibility with the API spec.

Consider updating __version__ to align with the v2.3.0 migration.

🔧 Proposed fix
-__version__ = "2.1.7.0"
+__version__ = "2.3.0.0"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/open_api/__init__.py` around lines 10 - 17, Update the package version
constant to match the OpenAPI document change: replace the current __version__
value ("2.1.7.0") with "2.3.0" in the module where __version__ is defined, and
ensure the module docstring/comment referencing the OpenAPI document version
remains consistent with the new value.
sdk/reya_rest_api/client.py (1)

186-237: ⚠️ Potential issue | 🟠 Major

Retain market-type validation in the unified order path.

After the refactor these methods only resolve market_id, so they no longer enforce the two market-specific rules called out in their own docstrings: trigger orders are perp-only, and reduceOnly must be omitted on spot. As written, a spot trigger order will still be signed/submitted, and a spot limit order with reduce_only=False still serializes reduceOnly=False, which the API rejects.

Proposed fix
 class ReyaTradingClient:
@@
     def __init__(self, config: Optional[TradingConfig] = None):
         self._symbol_to_market_id: dict[str, int] = {}
+        self._symbol_to_market_type: dict[str, str] = {}
         self._initialized = False
@@
     async def _load_market_definitions(self) -> None:
         """Load both perp and spot market definitions."""
         market_definitions: list[MarketDefinition] = await self.reference.get_market_definitions()
         self._symbol_to_market_id = {market.symbol: market.market_id for market in market_definitions}
+        self._symbol_to_market_type = {market.symbol: "perp" for market in market_definitions}
@@
         spot_market_definitions = await self.reference.get_spot_market_definitions()
         for market in spot_market_definitions:
             self._symbol_to_market_id[market.symbol] = market.market_id
+            self._symbol_to_market_type[market.symbol] = "spot"
@@
     async def create_limit_order(self, params: LimitOrderParameters) -> CreateOrderResponse:
@@
         market_id = self._get_market_id_from_symbol(params.symbol)
+        market_type = self._symbol_to_market_type[params.symbol]
         nonce = self._get_next_nonce()
@@
+        if market_type == "spot" and params.reduce_only is not None:
+            raise ValueError("reduce_only is only supported for perp markets")
+
         order_request = CreateOrderRequest(
@@
-            reduceOnly=reduce_only if params.reduce_only is not None else None,
+            reduceOnly=reduce_only if market_type == "perp" and params.reduce_only is not None else None,
@@
     async def create_trigger_order(self, params: TriggerOrderParameters) -> CreateOrderResponse:
@@
         market_id = self._get_market_id_from_symbol(params.symbol)
+        market_type = self._symbol_to_market_type[params.symbol]
+        if market_type != "perp":
+            raise ValueError("Trigger orders are only supported for perp markets")
         nonce = self._get_next_nonce()

Also applies to: 242-305

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/reya_rest_api/client.py` around lines 186 - 237, The unified order
methods (create_limit_order and the trigger-order method around lines 242-305)
must reintroduce market-type validation: use
_get_market_id_from_symbol(params.symbol) then fetch the market type (e.g., via
an existing helper like _get_market_by_id or a new
_is_perp_market/_is_spot_market) and enforce the rules — if creating a trigger
order ensure the market is perp and raise ValueError if not; for limit (and
other non-trigger) orders ensure that reduceOnly is omitted (pass None) when the
market is spot (do not serialize reduceOnly=False), otherwise allow reduceOnly
for perp markets; update the CreateOrderRequest construction (the reduceOnly and
any trigger-specific fields) accordingly so spot orders never include reduceOnly
and trigger orders are rejected on spot.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sdk/async_api/market_summary.py`:
- Around line 37-43: The long list literals assigned to known_object_properties
and known_json_properties in market_summary.py exceed the 120-char line limit;
split each list across multiple lines (one element per line or grouped
logically) or run the repo formatter so each list entry is on its own line,
preserving the same element order and names for known_object_properties and
known_json_properties so the behavior of the validation logic (the
unknown_object_properties check and later uses) is unchanged.

In `@sdk/async_api/order.py`:
- Line 18: The single long declaration for the dataclass field order_type (the
Field(...) call with alias='orderType') exceeds 120 characters; break the
Field(...) call across multiple lines so the description, alias and other
arguments are on separate indented lines (for example place description on its
own line and alias on another) to keep each line under 120 chars and preserve
the same parameters and types in the order_type definition.

In `@sdk/async_api/perp_execution.py`:
- Around line 11-12: The new Field declarations (taker_order_id and
maker_order_id) and the regenerated allowlist lines exceed the 120-character
line-length limit; rewrap the Field calls and long allowlist entries so they
stay within 120 columns (for example break long description/alias strings across
lines, use implicit line continuation via parentheses or split the allowlist
into multiple shorter lines) and then run the repository formatter (e.g., Black
with the project's line-length setting) to ensure the changes for symbols
taker_order_id, maker_order_id and the allowlist entries referenced around the
block at lines 49-55 conform to the 120-character rule.

In `@sdk/async_api/spot_market_summary.py`:
- Line 20: Replace non-idiomatic membership checks with Python's preferred
operators: change occurrences of "not key in serialized_self" to "key not in
serialized_self" and replace "known_json_properties.__contains__(obj_key)" with
"obj_key in known_json_properties". Update these checks where they appear around
the serialization logic (references: serialized_self, key,
known_json_properties, obj_key) to use the "in" / "not in" operators for clarity
and consistency.
- Around line 1-3: Remove the unexpected leading whitespace before the
module-level imports so the statement "from __future__ import annotations" and
the subsequent imports (e.g., model_serializer, model_validator, BaseModel,
Field) start at column 0; open the file spot_market_summary.py and fix the
top-of-file indentation so all import lines have no leading spaces and then run
a quick import/test to confirm the SyntaxError is resolved.

In `@sdk/open_api/api_client.py`:
- Line 8: The User-Agent sent at runtime is still hardcoded to
"OpenAPI-Generator/2.1.7.0/python"; locate the code in
sdk/open_api/api_client.py that builds request headers (look for the ApiClient
class and the place that sets "User-Agent" or the string
"OpenAPI-Generator/2.1.7.0/python") and update that literal to match the OpenAPI
document version (e.g., "OpenAPI-Generator/2.3.0/python"); ensure any
helper/constant used for the runtime user-agent is updated consistently so
requests from this SDK report the new 2.3.0 version.

In `@sdk/open_api/api/market_data_api.py`:
- Around line 2542-2584: The OpenAPI description for the spot-only method
get_spot_market_summary still uses the perpetual example "BTCRUSDPERP"; update
the parameter description/example to a spot symbol (e.g., "BTCUSD" or another
spot market symbol) so generated SDK docs show a spot symbol; locate and change
the annotated parameter in get_spot_market_summary (symbol: Annotated[str,
Field(... description="Trading symbol (e.g., BTCRUSDPERP")]) to use a spot
example, and apply the same edit pattern to the other spot-summary methods
referenced (the similar symbol Field descriptions in the blocks around lines
2611-2653 and 2680-2722) so all spot-only endpoints advertise a spot symbol
example.

In `@sdk/open_api/configuration.py`:
- Around line 496-501: The return statement in the debug report function uses
backslash line continuation causing implicit multiline string concatenation
(ISC002); replace the backslash-continued string with an explicit parenthesized
string literal so the format call still applies (i.e., rewrite the return in the
method that builds the "Python SDK Debug Report" to use a single parenthesized
string across lines and then call .format(env=sys.platform,
pyversion=sys.version)); ensure the produced string content and the .format
arguments (env and pyversion) remain unchanged.

In `@sdk/open_api/models/create_order_request.py`:
- Line 30: The module-level docstring in create_order_request.py (the
CreateOrderRequest model) has lines exceeding the 120-char policy; update the
OpenAPI generator configuration to set docstringMaxLineLength (or equivalent) so
generated docstrings are wrapped, then regenerate; alternatively, post-process
the generated create_order_request.py docstring to wrap long lines to <=120
characters (ensure the multi-line comment that documents OrderDetails,
isBuy/qty, deadline/expiresAfter and the EIP-712 reference is wrapped) and
commit the fixed file so the CreateOrderRequest documentation lines 30, 35, 41,
42, and 49 no longer exceed 120 chars.

In `@sdk/open_api/models/order_type.py`:
- Line 23: The docstring for the generated OrderType enum is longer than the
120-char line limit (it documents the on-chain OrderDetails.orderType values) —
fix this by updating the OpenAPI generator/template to wrap or hard-wrap long
enum descriptions (or enable formatter wrapping) so the generated OrderType
docstring is broken into lines ≤120 chars; adjust the generator config or the
template that emits the OrderType enum documentation to produce multi-line
docstrings for the OrderType symbol (referencing OrderDetails.orderType in the
description) rather than relying on a single long line.

In `@sdk/open_api/models/perp_execution.py`:
- Around line 36-55: The generated PerpExecution model contains several lines
exceeding the 120-char limit (notably declarations like taker_order_id,
maker_order_id, qty, price, the various fee/pnl fields and the __properties
ClassVar); run the repository Python formatter (e.g., black) or manually reflow
those long Field/Annotated declarations so each parameter and alias sits on its
own wrapped line (keep names: taker_order_id, maker_order_id, qty, price,
taker_fee, maker_fee, taker_opening_fee, maker_opening_fee, taker_realized_pnl,
maker_realized_pnl, taker_price_variation_pnl, maker_price_variation_pnl,
taker_funding_pnl, maker_funding_pnl, and __properties) to ensure no code line
exceeds 120 characters and retain existing types/aliases.

In `@sdk/reya_rest_api/auth/signatures.py`:
- Around line 51-54: Reject negative or lossy inputs up-front: in
_scale_e18(value) convert to Decimal, reject negatives and require exact
18-decimal scaling by computing scaled = dec * 10**18 and raising ValueError if
scaled is not an integer (i.e. scaled != scaled.to_integral_value()); in
sign_order(...) validate the qty argument is non-negative and that calling
_scale_e18(qty) will not silently truncate precision (propagate the exception)
before building typed data so inputs like 0.1234567890123456789 or a negative
sell quantity fail fast.

In `@sdk/reya_rest_api/client.py`:
- Around line 119-134: The _get_next_nonce method currently calls
self._config.owner_wallet_address.lower() unconditionally which raises
AttributeError when owner_wallet_address is unset; update
ReyaTradingClient._get_next_nonce to first validate that
self._config.owner_wallet_address is present/non-empty and if not raise a clear
configuration error (e.g., ValueError or a specific ConfigError) with a
descriptive message like "owner_wallet_address must be set to use nonce-based
operations" before calling .lower(), then proceed with the existing locking and
nonce logic using the validated/lowered wallet_address.

In `@sdk/reya_websocket/resources/market.py`:
- Around line 272-294: Add missing docstrings to the
MarketExecutionBustsResource and MarketExecutionBustsSubscription classes to
match the style of other resources: add class-level one-line descriptions for
MarketExecutionBustsResource and MarketExecutionBustsSubscription, and small
docstrings on their __init__ methods describing parameters (socket, symbol), the
for_symbol method describing input and return type (returns
MarketExecutionBustsSubscription), and subscribe/unsubscribe methods describing
behavior and parameters (batched for subscribe). Follow the same brief phrasing
and parameter/return conventions used by existing classes like
MarketSummaryResource and MarketDepthResource to ensure consistency.

In `@sdk/reya_websocket/resources/wallet.py`:
- Around line 297-319: Add missing docstrings to match the style used by other
wallet resource classes: document the WalletExecutionBustsResource class (brief
class description) and its __init__ and for_wallet methods, and document
WalletExecutionBustsSubscription and its __init__, subscribe, and unsubscribe
methods (describe parameters like socket, address, and batched, and what each
method does). Use the same concise phrasing and punctuation style as other
resources so the docstrings for WalletExecutionBustsResource,
WalletExecutionBustsSubscription, __init__, for_wallet, subscribe, and
unsubscribe are consistent with the rest of the file.

In `@specs`:
- Line 1: The specs entry records a pinned submodule SHA (653d108...) that
doesn't match the repository's current submodule HEAD (e2d33e4...), causing a
dirty submodule state; update the pinned SHA in the specs file to the actual
submodule commit (e2d33e4...) or reset the submodule to the pinned SHA, ensure
the working tree is clean, verify the submodule contains the expected files
(e.g., execution_bust.py and spot_market_summary.py) and then commit the
corrected submodule pointer (or update the specs entry) so the repo and specs
stay in sync before merging.

In `@tests/helpers/builders/order_builder.py`:
- Around line 299-305: Add missing docstrings to the TriggerOrderBuilder methods
reduce_only() and client_order_id(): for reduce_only, add a concise description
stating it marks the order as reduce-only, document the parameter value: bool
(default True), and the return type TriggerOrderBuilder; for client_order_id,
add a concise description saying it sets a numeric client-side order identifier,
document the parameter client_order_id: int and the return type
TriggerOrderBuilder. Keep wording and formatting consistent with the existing
builder method docstrings in the class.

In `@tests/test_orderbook/conftest.py`:
- Around line 40-47: The pytest CLI option --orderbook-perp-asset is never read;
update the perp_market_config fixture to use
request.config.getoption("orderbook-perp-asset") (or fallback to
os.environ.get("ORDERBOOK_PERP_ASSET")) instead of only reading the environment,
or alternatively remove the unused pytest_addoption definition; locate
pytest_addoption and perp_market_config in tests/test_orderbook/conftest.py and
implement the getoption path so the CLI flag is honored.
- Around line 97-101: The current except block in the fixture swallows errors
and sets a hardcoded oracle_price = 3000.0 which can cause flakiness; update the
except handling for maker_tester_session.data.current_price(symbol) so it either
(a) uses an asset-specific fallback map (e.g., ASSET_FALLBACKS.get(symbol) and
default to a safe sentinel) and logs which fallback was chosen via
logger.warning, or (b) re-raises or raises a custom exception to fail the
fixture instead of continuing with a possibly incorrect price; change the
oracle_price assignment and the logger.warning call accordingly to reference the
chosen fallback or the raised error.

In `@tests/test_orderbook/test_limit_orders.py`:
- Around line 57-85: The test_mass_cancel_clears_open_orders currently accepts
market_type but never uses it (Ruff ARG001); update the test to include
market_type in assertion messages for better diagnostics by (1) changing the
assert response.order_id is not None to include a message that references
market_type and market_config.symbol (so failures show which market type failed)
and (2) after each await maker_tester.wait.for_order_state(order_id,
OrderStatus.CANCELLED) add an explicit assert (or augment any existing
assertion) that the order state is CANCELLED with a failure message containing
market_type and order_id (use the test function name
test_mass_cancel_clears_open_orders and symbols like response.order_id,
order_id, market_type, market_config.symbol to locate where to add the
messages).

In `@tests/test_perps/test_position_management.py`:
- Line 12: Remove the module-level skip by deleting or disabling the pytestmark
= pytest.mark.skip(...) in test_position_management.py; instead, mark only the
specific failing tests (e.g., with `@pytest.mark.skip` or `@pytest.mark.xfail` on
the individual test functions that need it) or gate them behind a conditional
check for the matching-engine version, so the rest of the module still runs in
CI; ensure tests use pytest-recording/vcrpy decorators or fixtures (e.g.,
`@pytest.mark.vcr` or provided vcr_fixture) and keep coverage by running under
pytest-cov as per project test guidelines.

In `@tests/test_spot/test_api_validation.py`:
- Around line 13-21: The test module is entirely skipped via the pytestmark skip
marker which removes critical signature/nonce/deadline validation coverage;
remove the pytestmark skip and update the disabled tests to use the new signing
helpers (replace SignatureGenerator.encode_inputs_limit_order and
SignatureGenerator.sign_raw_order with sign_order, sign_cancel_order,
sign_mass_cancel) and the unified CreateOrderRequest/Cancels schema (rename
expiresAfter -> deadline where the signature deadline is populated), ensure
tests use pytest-recording/vcrpy for HTTP fixtures and include pytest-cov hooks
so they run under CI; locate the pytestmark variable and the old tests that
construct orders manually and rewrite them to call the new sign_* APIs and
unified request builders before re-enabling.

---

Outside diff comments:
In `@sdk/open_api/__init__.py`:
- Around line 10-17: Update the package version constant to match the OpenAPI
document change: replace the current __version__ value ("2.1.7.0") with "2.3.0"
in the module where __version__ is defined, and ensure the module
docstring/comment referencing the OpenAPI document version remains consistent
with the new value.

In `@sdk/open_api/models/create_order_response.py`:
- Line 34: The generated line for the field "order_id" in
create_order_response.py exceeds the 120-char limit; instead of editing this
generated line, update the OpenAPI generator/template configuration to enforce a
120-character max line length (wrap long Field descriptions or enable line
wrapping) so generated model fields like order_id: Optional[StrictStr] =
Field(..., description="...", alias="orderId") are emitted within 120 chars;
adjust the generator's mustache template or code formatter settings used in
generation so all future outputs conform to the 120-character guideline.

In `@sdk/open_api/models/market_definition.py`:
- Line 40: The __properties class variable declaration in MarketDefinition
exceeds the 120-character limit; split the list literal across multiple lines so
each line is ≤120 chars (e.g., one element per line or grouped) and then update
the OpenAPI/python generator template or its configuration that produces
sdk/open_api/models/market_definition.py so all generated **/*.py files format
__properties (and similar long lists) with line wrapping under 120 chars, then
regenerate the models to apply the fix; target symbols: __properties in the
MarketDefinition model (and the generator template that emits the class property
list).

In `@sdk/reya_rest_api/client.py`:
- Around line 186-237: The unified order methods (create_limit_order and the
trigger-order method around lines 242-305) must reintroduce market-type
validation: use _get_market_id_from_symbol(params.symbol) then fetch the market
type (e.g., via an existing helper like _get_market_by_id or a new
_is_perp_market/_is_spot_market) and enforce the rules — if creating a trigger
order ensure the market is perp and raise ValueError if not; for limit (and
other non-trigger) orders ensure that reduceOnly is omitted (pass None) when the
market is spot (do not serialize reduceOnly=False), otherwise allow reduceOnly
for perp markets; update the CreateOrderRequest construction (the reduceOnly and
any trigger-specific fields) accordingly so spot orders never include reduceOnly
and trigger orders are rejected on spot.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 15256755-34d8-4b77-9d78-2410319b37f9

📥 Commits

Reviewing files that changed from the base of the PR and between 84704f4 and e2d33e4.

📒 Files selected for processing (92)
  • .openapi-generator/FILES
  • examples/rest_api/perps/order_entry.py
  • pyproject.toml
  • sdk/async_api/execution_bust.py
  • sdk/async_api/execution_type.py
  • sdk/async_api/market_execution_bust_update_payload.py
  • sdk/async_api/market_summary.py
  • sdk/async_api/order.py
  • sdk/async_api/order_type.py
  • sdk/async_api/perp_execution.py
  • sdk/async_api/spot_market_summary.py
  • sdk/async_api/spot_market_summary_update_payload.py
  • sdk/async_api/spot_markets_summary_channel.py
  • sdk/async_api/spot_markets_summary_update_payload.py
  • sdk/async_api/wallet_execution_bust_update_payload.py
  • sdk/open_api/__init__.py
  • sdk/open_api/api/market_data_api.py
  • sdk/open_api/api/order_entry_api.py
  • sdk/open_api/api/reference_data_api.py
  • sdk/open_api/api/specs_api.py
  • sdk/open_api/api/wallet_data_api.py
  • sdk/open_api/api_client.py
  • sdk/open_api/configuration.py
  • sdk/open_api/exceptions.py
  • sdk/open_api/models/__init__.py
  • sdk/open_api/models/account.py
  • sdk/open_api/models/account_balance.py
  • sdk/open_api/models/account_type.py
  • sdk/open_api/models/asset_definition.py
  • sdk/open_api/models/cancel_order_request.py
  • sdk/open_api/models/cancel_order_response.py
  • sdk/open_api/models/candle_history_data.py
  • sdk/open_api/models/create_order_request.py
  • sdk/open_api/models/create_order_response.py
  • sdk/open_api/models/depth.py
  • sdk/open_api/models/depth_type.py
  • sdk/open_api/models/execution_bust.py
  • sdk/open_api/models/execution_bust_list.py
  • sdk/open_api/models/execution_type.py
  • sdk/open_api/models/fee_tier_parameters.py
  • sdk/open_api/models/global_fee_parameters.py
  • sdk/open_api/models/level.py
  • sdk/open_api/models/liquidity_parameters.py
  • sdk/open_api/models/market_definition.py
  • sdk/open_api/models/market_summary.py
  • sdk/open_api/models/mass_cancel_request.py
  • sdk/open_api/models/mass_cancel_response.py
  • sdk/open_api/models/order.py
  • sdk/open_api/models/order_status.py
  • sdk/open_api/models/order_type.py
  • sdk/open_api/models/pagination_meta.py
  • sdk/open_api/models/perp_execution.py
  • sdk/open_api/models/perp_execution_list.py
  • sdk/open_api/models/position.py
  • sdk/open_api/models/price.py
  • sdk/open_api/models/request_error.py
  • sdk/open_api/models/request_error_code.py
  • sdk/open_api/models/server_error.py
  • sdk/open_api/models/server_error_code.py
  • sdk/open_api/models/side.py
  • sdk/open_api/models/spot_execution.py
  • sdk/open_api/models/spot_execution_list.py
  • sdk/open_api/models/spot_market_definition.py
  • sdk/open_api/models/spot_market_summary.py
  • sdk/open_api/models/tier_type.py
  • sdk/open_api/models/time_in_force.py
  • sdk/open_api/models/wallet_configuration.py
  • sdk/open_api/rest.py
  • sdk/reya_rest_api/auth/signatures.py
  • sdk/reya_rest_api/client.py
  • sdk/reya_rest_api/config.py
  • sdk/reya_rest_api/constants/enums.py
  • sdk/reya_rest_api/models/orders.py
  • sdk/reya_websocket/resources/market.py
  • sdk/reya_websocket/resources/wallet.py
  • sdk/reya_websocket/socket.py
  • specs
  • tests/helpers/builders/order_builder.py
  • tests/helpers/reya_tester/checks.py
  • tests/helpers/reya_tester/data.py
  • tests/helpers/reya_tester/waiters.py
  • tests/helpers/reya_tester/websocket.py
  • tests/test_orderbook/__init__.py
  • tests/test_orderbook/conftest.py
  • tests/test_orderbook/test_execution_busts.py
  • tests/test_orderbook/test_limit_orders.py
  • tests/test_perps/test_dynamic_pricing.py
  • tests/test_perps/test_limit_orders.py
  • tests/test_perps/test_position_management.py
  • tests/test_perps/test_trigger_orders.py
  • tests/test_spot/test_api_validation.py
  • tests/test_spot/test_spot_execution_busts.py
💤 Files with no reviewable changes (4)
  • sdk/reya_rest_api/constants/enums.py
  • tests/test_spot/test_spot_execution_busts.py
  • sdk/reya_rest_api/config.py
  • tests/test_perps/test_dynamic_pricing.py

Comment thread sdk/async_api/market_summary.py
Comment thread sdk/async_api/order.py
Comment thread sdk/async_api/perp_execution.py
Comment thread sdk/async_api/spot_market_summary.py Outdated
Comment thread sdk/async_api/spot_market_summary.py
Comment thread tests/test_orderbook/conftest.py
Comment thread tests/test_orderbook/conftest.py Outdated
Comment thread tests/test_orderbook/test_limit_orders.py Outdated
Comment thread tests/test_perps/test_position_management.py Outdated
Comment thread tests/test_spot/test_api_validation.py Outdated
Reflects the new devnet1 environment in reya-devops (perpOB-enabled testnet
that replaces cronos). Defaults flip to api-devnet.reya-cronos.network /
websocket-devnet.reya-cronos.network; chain id stays 89346162.

Resolves the three pytest.mark.skip TODOs from the previous commit:

- tests/test_perps/test_limit_orders.py — rewritten with the maker/taker
  pattern (PERP_ACCOUNT_ID_1 rests GTC, PERP_ACCOUNT_ID_2 IOCs through it).
  Covers IOC fills, GTC resting, reduce_only-without-position rejection, and
  perp mass-cancel (newly supported under perpOB).

- tests/test_perps/test_position_management.py — rewritten as maker/taker
  open-long, open-short, increase-long, and reduce-only close.

- tests/test_spot/test_api_validation.py — wholesale skip removed; all 26
  signature/nonce/deadline tests ported to sign_order / sign_cancel_order
  and the renamed `deadline` field on CreateOrder/Cancel/MassCancel
  requests. test_spot_order_missing_expiration → test_spot_order_missing_deadline
  to reflect the v2.3.0 schema rename.

Infra:
- ReyaTester gains a perp_account_number arg (mutually exclusive with
  spot_account_number) and a shared _create_client_for_account helper.
- tests/conftest.py adds perp_maker_tester_session / perp_taker_tester_session
  and their function-scoped wrappers, mirroring the spot maker/taker pattern.
- .env.example documents PERP_ACCOUNT_ID_2 / PRIVATE_KEY_2 / WALLET_ADDRESS_2.

Also fixes a Modelina codegen indent bug in sdk/async_api/spot_market_summary.py.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

… AMM tests

test_perps/test_market_data.py
- Port to the v2.3.0 MarketSummary schema: oi_qty (single, no long/short
  split), no funding_rate_velocity, throttled_oracle_price → mark_price,
  throttled_pool_price → throttled_mid_price.
- Tolerate Price.pool_price being None on perpOB-only markets where the
  AMM pool-price publisher no longer ticks.
- Update test_market_perp_executions for v2.3.0 PerpExecution: taker_fee /
  taker_account_id renames + DUST execution type.

test_orderbook/ — five new shared lifecycle test files
- conftest.py: PerpTestConfig now mirrors SpotTestConfig's full liquidity-
  detection surface (refresh_order_book, has_*_liquidity, best_*_price,
  circuit_breaker_*, get_usable_*_price_for_qty, safe-no-match prices).
  Adds parametrized `maker` and `taker` fixtures that select the right
  ReyaTester based on `market_type`.
- test_order_cancellation.py: cancel by order_id, mass-cancel, cancel-of-
  cancelled, cancel of unknown order_id (the last from old AMM coverage).
- test_self_match_prevention.py: GTC/IOC self-match prevention plus a
  cross-account sanity match. Skips when external liquidity could
  interfere with the controlled-book assertions.
- test_websocket_events.py: orderChanges on create + cancel, depth
  subscription liveness. Balance-update verification stays in test_spot/
  (perp settles to positions, not asset balances).
- test_ioc_orders.py: full fill against resting maker, no-liquidity IOC
  unfills immediately, partial-fill IOC drops the remainder.
- test_maker_taker_matching.py: end-to-end maker→taker match with REST
  depth check and WS order-changes / execution events. Spot-specific
  balance-delta assertions stay in tests/test_spot/.

test_perps/test_position_management.py — recover transferrable AMM coverage
Adds increase_short, partial_close_long / _short, and decrease_without_
reduce_only — adapted from the old AMM single-account flow to the new
maker/taker pattern using the perp_maker_tester / perp_taker_tester
fixtures.

GitHub issue #52 tracks the RPC-layer follow-up (OrdersGatewayProxy ABI,
settle_fill / cancel_nonce actions, PassivePerpExecutionV3 decoder).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

Run pre-commit equivalents in a fresh venv (Python 3.9.6 — only version
available locally; project targets 3.12+ for execution but 3.10 for mypy).

Mechanical fixes:
- black reformat: 8 files, all length/wrap differences picked up by black 24.10
  vs whatever ran before.
- isort fix: signatures.py import ordering.
- mypy: drop the now-unused ``# type: ignore[attr-defined]`` on the websocket
  import (newer websocket-client exposes WebSocket/WebSocketApp directly), and
  silence four ``arg-type`` mismatches in ``ReyaSocket.__init__`` where the
  public callbacks are typed against ``WebSocket`` for callsite ergonomics
  while WebSocketApp expects ``WebSocketApp`` as the first arg — interchangeable
  at runtime.
- flake8: drop two F401 unused imports introduced by my recent ports
  (``OrderStatus`` in test_ioc_orders.py, ``ReyaTester`` in test_orderbook
  conftest).
- pylint: add ``# pylint: disable=redefined-outer-name`` on the
  market_config/maker/taker fixtures (standard pytest fixture-injection
  pattern, mirrors how tests/conftest.py handles it). Use ``_ = market_type``
  in the two test bodies that depend on the [spot, perp] parametrization but
  don't reference the param explicitly, so unused-argument doesn't fire.

Final state with the project flake8 ignores (E501, E203, W503):
- black --check: 120 files unchanged
- flake8: clean
- mypy: 16 source files, no issues
- pylint on test_orderbook: 10.00/10

Pre-existing pylint quirks not addressed (unrelated to this migration):
- ``no-value-for-parameter`` false positive on ``Account.from_key(...)`` —
  pylint doesn't pick up eth_account's classmethod signature.
- ``unsupported-binary-operation`` (E1131) on ``int | None`` annotations in
  pre-existing test files — only fires on Python 3.9; project runs 3.12.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

Run the project's full pre-commit hook chain (pyupgrade, isort, black, flake8,
bandit, pylint, mypy, poetry-check, yamlfmt, jsonschema) end-to-end on Python
3.12. Everything passes.

Fixes the migration introduced or exposed:

- pyupgrade auto-rewrote ``Union[A, B]`` → ``A | B`` across the new
  test_orderbook/ files; dropped the now-unused ``from typing import Union``.
- sdk/reya_websocket/socket.py: restored the ``# type: ignore[attr-defined]``
  on the websocket-client import (mypy stubs in the project's poetry env still
  don't expose ``WebSocket``/``WebSocketApp`` directly), dropped the
  ``# type: ignore[arg-type]`` shims I added in the previous lint pass (no
  longer needed once the attr-defined ignore is back), and ``cast(...)`` the
  five ``model_validate`` returns in ``_parse_message`` to match the existing
  channel_data branch.
- sdk/reya_rest_api/client.py: ``cast(...)`` every ``await self.<api>.<m>(...)``
  return so the public methods stop bleeding ``Any`` from the openapi-generated
  surface (mypy.overrides ignores ``sdk.open_api.*``, which makes its return
  types Any to the rest of the codebase).
- tests/test_orderbook/conftest.py: assert ``market_def is not None`` after the
  pytest.skip narrows the Optional, drop a stale ``# type: ignore``, and pin
  ``request.param`` to ``str`` via an annotated local.
- tests/test_orderbook/test_execution_busts.py: bind the websocket reference to
  a local + assert it's not None after the early skip so the loop body type-
  checks against ``ReyaSocket``.
- tests/test_perps/test_trigger_orders.py + examples/rest_api/perps/order_entry.py:
  pass the now-required ``symbol`` (and ``account_id``) to ``cancel_order``;
  matches the v2.3.0 client signature.
- tests/test_spot/test_api_validation.py: assert balance is not None after the
  Optional pytest.skip pattern in the two insufficient-balance tests.

Pre-existing-on-main fixes hoovered up while in the area:

- sdk/reya_rpc/utils/execute_core_commands.py: drop a ``# type: ignore[no-any-return]``
  that's now unused (mypy resolves the Web3 receipt type without it).
- tests/test_spot/test_state_resilience.py: assert ``order_id is not None``
  before using it as a dict key / EventStore lookup arg.

Config:

- pyproject.toml: bump pylint ``max-module-lines`` from 2000 to 2050. The
  ported test_api_validation.py is at 2002 lines after the v2.3.0 sign_order
  rewrite added per-test ``Decimal()`` wrappers; the file's coherent and the
  former limit was arbitrary.

Verified end-to-end with ``pre-commit run --all-files`` on Python 3.12.13 in a
clean venv with the project's poetry deps installed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

…tgun

Adversarial review surfaced two real issues; rest of the agent's findings were
either already covered or refuted by checking the canonical TS SDK at
reya-off-chain-monorepo/packages/sdk/src/services/orders/orderV2.ts.

1. sdk/reya_websocket/socket.py — wire up the spot market summary channels.

The AsyncAPI spec defines /v2/spotMarkets/summary and /v2/spotMarket/{symbol}/summary
and the regen produces SpotMarketSummaryUpdatePayload + SpotMarketsSummaryUpdatePayload,
but the dispatcher had no case for them. Subscribing today raised
``WebSocketDataError: Unknown channel`` even though the channel is valid. Adds the
imports, extends WebSocketMessage, the exact-match table, and the parameterized
``/v2/spotMarket/.../summary`` branch in _get_payload_type.

2. sdk/reya_rest_api/models/orders.py — make TriggerOrderParameters.qty required.

The previous default of qty="0.01" existed only to keep the inherited
test_perps/test_trigger_orders.py compiling without rewrites. Production users
calling create_trigger_order(...) without qty would silently sign a 0.01-sized
stop-loss / take-profit even when their actual position was larger, leaving them
with the wrong risk after the trigger fires. There's no safe default for "size of
my open position" — make it explicit. Updates the 14 callsites in
test_trigger_orders.py and the 4 in examples/rest_api/perps/order_entry.py to
pass qty="0.01" matching the 0.01-sized positions those tests actually open.

Verified that pre-commit (pyupgrade, isort, black, flake8, bandit, pylint, mypy,
poetry-check, yamlfmt, jsonschema) is clean on Python 3.12.13.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

Confirms the Python sign_order / sign_cancel_order / sign_mass_cancel helpers
in sdk/reya_rest_api/auth/signatures.py produce byte-identical signatures to
the canonical TypeScript impl in
reya-off-chain-monorepo/packages/common/src/transactions/sign.ts.

Layout:
- tests/parity/sign_ts.mjs — node script using ethers v6 signTypedData against
  pinned typed-data definitions (orderTypes, orderCancelTypes, massCancelTypes
  copied verbatim from the TS source) and a fixed payload + hardhat test key.
  Outputs JSON with the three signature hex strings.
- tests/parity/test_signature_parity.py — pytest with the TS-generated hex
  hardcoded in EXPECTED_SIGNATURES; exercises the Python helpers with the
  same inputs and asserts byte equality.
- tests/parity/README.md — how to run and how to regenerate when the TS impl
  evolves.
- tests/parity/package.json + package-lock.json — pin ethers v6 for the harness.
  node_modules/ is already in .gitignore.

Test vector: hardhat well-known key 0xac09…ff80 (signer 0xf39F…2266) signing
against the testnet OrdersGateway 0x5a0a…7ca5 on chain id 89346162. The Order
covers a LIMIT IOC perp buy with all 13 OrderDetails fields populated; the
OrderCancel and MassCancel exercise the compact uint64 envelopes including
mass_cancel's marketId=0 ("cancel all markets") fallback that matches the TS
SDK's params.marketId ?? 0 in massCancelMEOrders.

Verified locally: all three parity assertions pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

…ketSummary

PerpExecution split account_id/fee into taker_*/maker_*; MarketSummary lost
long_oi_qty/short_oi_qty/throttled_oracle_price/throttled_pool_price and
gained mark_price/throttled_mid_price. Update the WS monitoring examples and
ReyaTester helpers (matchers, perp_trade_context, checks, websocket) to read
from the new schema. Match perp executions on either taker or maker
account_id since the expected order's account is on one side of the trade.

Fixes mypy attr-defined errors in CI Lint / pre-commit (3.10).
- sdk/reya_rest_api/client.py: drop 12 cast(...) wrappers — the openapi
  client methods already return the typed result, mypy was flagging them
  as redundant-cast.
- tests/helpers/reya_tester/data.py: same for cast(Depth, ...).
- sdk/reya_rpc/utils/execute_core_commands.py: web3.eth.* returns Any,
  cast the receipt to TxReceipt at the boundary so the annotated return
  type is honored (no-any-return).
- tests/parity/test_signature_parity.py: black wanted the assert messages
  inlined instead of paren-wrapped; also pin a file-level pylint disable
  for redefined-outer-name (the standard pytest-fixture pattern that
  pylint W0621 can't tell apart from real shadowing).

Fixes the remaining mypy errors and the black + pylint hooks in CI.
Pylint on lower Python versions (and on user-class A | B unions in non-
annotation contexts) flags E1131 unsupported-binary-operation. Adding
`from __future__ import annotations` makes annotations lazy strings
(PEP 563), so pylint never tries to runtime-evaluate the union and the
issue disappears regardless of pylint host version. This matches the
convention already used elsewhere in the repo
(e.g. tests/test_perps/test_position_management.py).
…trings

- sdk/reya_rest_api/auth/signatures.py: reject negative qty in sign_order.
  Caller is expected to pass unsigned qty + is_buy to set direction; a
  negative qty would silently flip direction via `qty if is_buy else -qty`.
  Fail fast with ValueError instead.
- tests/test_orderbook/conftest.py: wire --orderbook-perp-asset CLI flag
  through request.config.getoption so it actually does something (was dead
  code; fixture only read the env var). Drop the silent 3000.0 oracle-price
  fallback — a wrong oracle price invalidates every downstream test, so
  let the OSError/ValueError surface.
- sdk/reya_websocket/resources/{market,wallet}.py: add docstrings on the
  new ExecutionBusts resource/subscription classes for parity with the
  surrounding resources.
- tests/helpers/builders/order_builder.py: docstrings on new reduce_only()
  and client_order_id() trigger-builder methods.
@github-actions

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

@arturbeg

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

CI is green except version-consistency (specs-tag follow-up — see Known issues in the PR description). All inline review comments have been replied to with addressed/declined rationale. Please re-assess.

@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown

@arturbeg Sure, I'll kick off a fresh review pass. Noted that CI is green except for the version-consistency check (specs-tag follow-up, documented as a known issue in the PR description), and that all prior inline comments have been addressed or declined with rationale.

Re-review requested by @arturbeg. CI is green except version-consistency (known issue — specs-tag follow-up documented in PR description). All prior inline comments have been replied to with addressed/declined rationale.

✅ Actions performed

Full review triggered.

CI's pyupgrade hook rewrote Optional[X]/Union[A,B] → X | None / A | B in
the three files we just touched with `from __future__ import annotations`,
which made the corresponding `from typing import Optional, Union` imports
truly unused (flake8 F401, pylint W0611).

Apply the rewrites locally and drop the now-unused imports so pre-commit
stays green from a clean tree.
@github-actions

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

@github-actions

github-actions Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

arturbeg and others added 3 commits May 31, 2026 21:37
The non-mainnet default verifyingContract (0x5a0a...) is the older reya_cronos
deployment and is stale for devnet1, where the live OrdersGateway is
0x7Ec89E555c771D2B5939aBE5C4E4291852633D4D — confirmed by reya-devops
(ORDERS_GATEWAY_PROXY_ADDRESS across every devnet1 service incl. ws-exec) and
the reya-deployments reya_devnet fork test. With REYA_ORDERS_GATEWAY unset, the
SDK signed against the wrong contract and the matching engine rejected every
order with an opaque "invalid signature" error.

- config.py: point the non-mainnet baked-in default at the devnet1 gateway.
- .env.example: set REYA_ORDERS_GATEWAY for devnet1 (+ commented mainnet value)
  so following the example works out of the box.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…test_spot_extreme_price

The ~1e9 "Insufficient balance for spot order" warns on devnet1 trace back to
this error-handling test signing a 1e12 limit price (qty × 1e12 ≈ 1e9), not a
real bug (Linear PRO-160, closed not-a-bug). Server-side the spot balance check
runs before px/qty validation, so an out-of-bounds price surfaces as
"Insufficient balance" rather than "price exceeds maximum". Noted inline with a
pointer to the low-priority server reorder (reya-off-chain-monorepo#2669) so the
next person seeing those warns finds the answer instead of re-investigating.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…id collision

Per review — the previous commit dropped the cronos testnet address. There are
only two chains (cronos 89346162, mainnet 1729); devnet1 reuses the cronos chain
id with a different OrdersGateway, so they can't be auto-distinguished by chain
id. Restructure to keep all three addresses explicit (mainnet / cronos_testnet /
devnet1) in one map, default non-mainnet to devnet1 (the current perpOB target),
and document that cronos is reachable via REYA_ORDERS_GATEWAY. .env.example:
devnet1 now works by default, so the override is commented (shown for clarity).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

📝 Manual version changes detected

✅ Version validation passed: 2.3.3.0

  • Version progression validated (no regression)
  • Version bump is reasonable (≤ 1 increment per component)

arturbeg and others added 4 commits May 31, 2026 22:03
Per review — cronos is a separate (not legacy) environment. It shares devnet1's
chain id (89346162) but has its own endpoints (api-cronos.reya.xyz,
websocket-testnet/ws-exec-testnet.reya.xyz) and gateway, sourced from the
reya-devops cronos deployment. Give it a distinct, parallel .env.example block
instead of burying it in the devnet1 section's comment, and call it "cronos
testnet" rather than "legacy".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…llback

Drop the dict whose "cronos_testnet" key was never selected. Define the three
gateways as named module constants, resolve via REYA_ORDERS_GATEWAY (set per
environment in .env.example) with a simple mainnet/devnet1 fallback by chain id;
cronos is reached via the explicit override (it shares devnet1's chain id).
.env.example: the devnet1 gateway is now set explicitly alongside the URLs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fix devnet1 OrdersGateway address (stale default broke EIP-712 signing)
@github-actions

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

📝 Manual version changes detected

✅ Version validation passed: 2.3.3.0

  • Version progression validated (no regression)
  • Version bump is reasonable (≤ 1 increment per component)

…ified on devnet

The ME now echoes the cancelled order's resolved orderId on a successful
clientOrderId cancel (PRO-143, deployed to devnet1), so the server response
satisfies the orderId-required CancelOrderResponse schema. Removed the xfail
marker so `test_spot_cancel_by_client_order_id` is a real regression guard —
confirmed passing in the full devnet1 suite (175 passed, 0 failed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

📝 Manual version changes detected

✅ Version validation passed: 2.3.3.0

  • Version progression validated (no regression)
  • Version bump is reasonable (≤ 1 increment per component)

…y (PRO-164)

PRO-164 changed the devnet1 OrdersGateway (config now returns
0x7Ec89E…633D4D) — the EIP-712 verifyingContract for order/cancel signing.
The offline signature-parity vectors were pinned to the old 0x5a0a… address,
so the setup assertion (config == pinned OrdersGateway) errored on all 5 parity
tests after the PRO-164 merge (#56).

Regenerated the TS-reference signatures via `node sign_ts.mjs` against the new
OrdersGateway and re-pinned them; updated ORDERS_GATEWAY in both sign_ts.mjs and
test_signature_parity.py. All 5 parity tests pass — Python↔TS EIP-712 parity
re-confirmed at the new address (no signing drift from the OrdersGateway change).
0x7Ec8… is the verified-correct devnet1 OrdersGateway (the full devnet1 suite
signs + settles orders with it).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

📝 Manual version changes detected

✅ Version validation passed: 2.3.3.0

  • Version progression validated (no regression)
  • Version bump is reasonable (≤ 1 increment per component)

…dity

`test_perp_reduce_only_rejected_without_position` rests a setup maker SELL at
oracle*1.04 to give the reduce-only IOC a counterparty. When the shared devnet
book has external liquidity (an MM bot quoting near pool price, ~+16% over
oracle), that maker SELL crosses immediately instead of resting, and settling
the resulting fill against the external counterparty currently 500s (off-chain
settlement-robustness bug, PRO-191) — so the test fails hard instead of skipping.

Add the same `skip_if_external_liquidity` guard its siblings already use (e.g.
`test_perp_ioc_taker_buy_matches_maker_sell`) so it self-skips on a dirty book.
Verified: the test now SKIPS cleanly against the live devnet book.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

📝 Manual version changes detected

✅ Version validation passed: 2.3.3.0

  • Version progression validated (no regression)
  • Version bump is reasonable (≤ 1 increment per component)

…from expiresAfter

- Sign postOnly as part of the EIP-712 OrderDetails (immediately after
  reduceOnly) via a shared _ORDER_DETAILS_TYPE; add GTT to the signing
  TimeInForce enum; sign_order takes an optional post_only.
- Decouple deadline (entry-only signature validity) from expiresAfter
  (order lifetime; 0 = perpetual) and drop the far-future-lifetime stopgap.
  Only GTT carries a non-zero expiresAfter (which must exceed the deadline);
  GTC and IOC always sign 0.
- Gate post_only: rejected on IOC, and rejected pending end-to-end wire +
  settlement support (postOnly=false signs and verifies identically today).
- Add post_only to LimitOrderParameters.
- Tests: golden OrderDetails struct-hash parity vs the on-chain canonical
  value; regenerate TS<->Py signature parity vectors to 14 fields (+ a
  postOnly vector); wire-serialization tests for the decoupling and the
  post_only gates.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

📝 Manual version changes detected

✅ Version validation passed: 2.3.3.0

  • Version progression validated (no regression)
  • Version bump is reasonable (≤ 1 increment per component)

…es pending off-chain

- Bump the specs submodule to api-specs feat/perpOB (postOnly on CreateOrderRequest,
  GTT in the TimeInForce enum) and regenerate open_api/. The wire model now
  transports postOnly (previously dropped) and exposes GTT. The sync also pulls in
  the branch's perp-route aliases and a doc-version bump to 3.0.1 — generated-code
  churn, not behavioral.
- client.py: add a GTT entry gate (reject pending off-chain support, avoiding a
  KeyError on the GTC/IOC-only TIF map) and refresh the postOnly gate rationale now
  that the model carries the field. The only remaining blocker for post_only=True /
  GTT is the off-chain 14-field digest reconstruction; default-False postOnly and
  GTC/IOC are unaffected.
- tests: add a GTT-rejection guard; update the postOnly-gate test wording.

Staging only — un-gating is a one-line change once the off-chain side reconstructs
14 fields.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

Version check passed

  • SDK version: ``
  • Specs tag: ``
  • All consistency checks passed

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

📝 Manual version changes detected

✅ Version validation passed: 2.3.3.0

  • Version progression validated (no regression)
  • Version bump is reasonable (≤ 1 increment per component)

The specs submodule now pins the api-specs 3.0.1 release tag (postOnly/GTT), so
the SDK package version is bumped to match the spec version prefix per the
Version Check policy. Regenerated open_api/ version strings accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

📝 Manual version changes detected

✅ Version validation passed: 3.0.1.0

  • Version progression validated (no regression)
  • Version bump is reasonable (≤ 1 increment per component)

The ws-exec createOrder frame $refs CreateOrderRequest, so the AsyncAPI-generated
models also carry postOnly + GTT now. Keeps the committed generated code in sync
with a fresh generate-ws.sh run (CI enforces this).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

📝 Manual version changes detected

✅ Version validation passed: 3.0.1.0

  • Version progression validated (no regression)
  • Version bump is reasonable (≤ 1 increment per component)

Cover the order/cancel validation gates without a devnet round-trip:
- reduce_only rejected on spot and on TP/SL trigger orders
- cancel rejected with neither order_id nor client_order_id
- cancel accepts both ids and carries both on the wire (server resolves precedence)
Complements the existing post_only / GTT / IOC entry-gate guards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

📝 Manual version changes detected

✅ Version validation passed: 3.0.1.0

  • Version progression validated (no regression)
  • Version bump is reasonable (≤ 1 increment per component)

@arturbeg arturbeg changed the title feat(perpOB): migrate Python SDK to v2.3.0 unified spot+perp API PerpOB Jun 5, 2026
…r rule

The five signature/nonce validation tests hand-build raw GTC order requests
(to inject a bad signature or nonce) and hardcoded expiresAfter=deadline,
signing the same value. Now that lifetime is decoupled from deadline, the
server rejects a non-zero expiresAfter on IOC/GTC/TP-SL orders with an input
validation error before reaching the signature/nonce check each test targets,
so all five failed on the wrong layer.

Set expiresAfter=0 on the wire and expires_after=0 in the matching signature
(so it recovers against the same envelope), and replace the now-inverted
comments. This fixes the tests and confirms the decoupling is enforced
end-to-end on the server.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

🤖 SDK Version Check

📝 Manual version changes detected

✅ Version validation passed: 3.0.1.0

  • Version progression validated (no regression)
  • Version bump is reasonable (≤ 1 increment per component)

@danigr99727 danigr99727 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review — perpOB migration (signing + client rewrite)

The EIP-712 signing rewrite is cryptographically correct. I verified OrderDetails (14 fields), the chainId-free domain, the OrderCancel/MassCancel envelopes, and the OrderType/TimeInForce enums byte-for-byte against the canonical sources: reya-network orders-gateway/src/libraries/OrderHashing.sol + utils/contracts/src/storage/Signature.sol (feat/perpOB, OrderHashing.sol@6d9b3b3fa) and the off-chain cancel verifier common-backend/src/eip712/cancel-types.ts. The golden-vector + TS↔Python parity harness is the right way to guard this.

Inline comments below cover the Critical + Important findings. Two items have no single line to attach to:

🔴 Critical — signature tests don't run in CI. The only workflows are pylint, version-consistency, publish-to-pypi, create-release — none invoke pytest. The golden/parity suite in tests/parity/ (the sole automated guard against EIP-712 field drift) is fully offline and runs in <10s. Please add poetry run pytest tests/parity/ to a PR workflow — otherwise a reordering of _ORDER_DETAILS_TYPE stays green in CI and only breaks on devnet.

📝 The PR description is stale in 3 places (will mislead whoever merges): "13-field" → actually 14 (postOnly added on-chain 2026-06-04); specs pin 653d108 → actually 62055120; the three test files described as "marked pytest.mark.skip" are not skipped (they hold 4 / 8 / 26 live tests).

⚠️ One integration question to resolve before live order placement: the SDK signs 14-field unconditionally and gates post_only=True/GTT off "until off-chain reconstructs 14-field". A cross-repo check found the off-chain verifier is still 13-field — and because adding postOnly changes the OrderDetails typehash, a 13-field reconstruction would reject even postOnly=False signatures (this only reconciles if create-sigs are verified solely on-chain at settlement, which is 14-field and matches). Please confirm the create-path verification site + deploy sequencing.

Automated review via Claude Code — please apply judgment and flag any false positives.

payload, _nonce = self.build_create_trigger_order_payload(params)
order_request = CreateOrderRequest(**payload)
return await self.orders.create_order(create_order_request=order_request)
return await self.orders.create_order(create_order_request=CreateOrderRequest(**payload))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔴 Critical — a silently-rejected order returns as success. CreateOrderResponse.status is a required OrderStatus that includes REJECTED, and order_id is Optional, but this returns the response unchecked. A 200 OK body carrying status=REJECTED, orderId=null is indistinguishable from a placed order — the trader believes they're resting/filled when they aren't.

resp = await self.orders.create_order(create_order_request=CreateOrderRequest(**payload))
if resp.status == OrderStatus.REJECTED:
    raise OrderRejectedError(f"Order rejected by matching engine: {resp}")
return resp

Cheap and correct whether or not the server uses 200 for rejects. (Compounds with the 13/14-field off-chain question in the review summary: if a 14-field sig is bounced by a 13-field verifier and the bounce comes back as 200+REJECTED, every order silently "succeeds".)

supported by the API.
"""
payload, _nonce = self.build_create_trigger_order_payload(params)
return await self.orders.create_order(create_order_request=CreateOrderRequest(**payload))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔴 Critical — same class as the create_limit_order comment, and the stakes are higher here. create_trigger_order also returns unchecked, and it hardcodes expiresAfter=0 precisely so the TP/SL protects the position indefinitely. A silently-rejected stop-loss (200+REJECTED) leaves the trader believing they're protected when they're not — the worst failure mode for a trading client. Guard on resp.status == OrderStatus.REJECTED (and order_id is None) before returning.

"""Unsubscribe from wallet execution busts."""
self.socket.send_unsubscribe(channel=self.path)


Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 Important — WalletBalancesResource registers a channel it can't parse. Just below, __init__ (line 356) registers the template "/v2/wallet/{address}/balances", but WalletBalancesSubscription.path (line 382) is "/v2/wallet/{address}/accountBalances", and socket.py _get_payload_type only recognizes the …/accountBalances suffix. The live path (WalletResource.balances() → the Subscription) round-trips fine, but the inherited WalletBalancesResource.subscribe() would send …/balances → server rejects / WebSocketDataError("Unknown channel"). Dead today only because nothing calls it directly — a trap for the next caller. Fix: line 356 should use "/v2/wallet/{address}/accountBalances" to match the Subscription + parser.

return REYA_DEX_ID

@property
def default_orders_gateway_address(self) -> str:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 Important — an unknown chain_id silently signs against the wrong gateway. TradingConfig is not frozen, and chain_id has no valid-range type: an unrecognized value falls through here to the devnet1 gateway, and cronos shares chain-id 89346162 with devnet1 (so it relies on the REYA_ORDERS_GATEWAY override). A wrong verifyingContract silently invalidates every signature. Suggest @dataclass(frozen=True) and raising on an unknown chain instead of a silent fallback.

@@ -0,0 +1,75 @@
"""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 Important — execution-bust field coverage regressed. The deleted tests/test_spot/test_spot_execution_busts.py had ~12 tests asserting per-record fields (reason, side ∈ {B,A}, qty>0, timestamp>0, wallet-vs-market consistency, pagination). This replacement (3 tests) checks only the list-envelope shape. The docstring acknowledges busts aren't deliberately triggered yet — reasonable as a transitional gap, but please file the follow-up so the field-level assertions come back.

return hash_uint256

def sign_raw_order(
def sign_order(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 Important — the IntEnums are defined but bypassed at the boundary that matters. sign_order(order_type: int, ..., time_in_force: int) takes raw int, so OrderTypeInt/TimeInForceInt (above) provide no safety here — a wrong int = a wrong signed order type. IntEnum is an int subtype, so annotating order_type: OrderTypeInt, time_in_force: TimeInForceInt is a runtime no-op but lets mypy catch a bad caller (it would also flag the bare order_type=0 literals in the tests).

is_buy: bool
qty: str
trigger_px: str
trigger_type: OrderType

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 Important — TriggerOrderParameters can be constructed in an illegal state. trigger_type: OrderType admits OrderType.LIMIT, which is incoherent for a trigger order and is only caught later at runtime inside the builder. Move the invariant to construction:

def __post_init__(self):
    if self.trigger_type not in (OrderType.STOP_LOSS, OrderType.TAKE_PROFIT):
        raise ValueError(f"trigger_type must be STOP_LOSS or TAKE_PROFIT, got {self.trigger_type!r}")

Comment thread AGENTS.md

Create `.env` file with:
```
ACCOUNT_ID=your_account_id

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 Important — this setup block won't start the SDK. TradingConfig.from_env() reads PERP_ACCOUNT_ID_1 / PERP_PRIVATE_KEY_1 / PERP_WALLET_ADDRESS_1, not ACCOUNT_ID / PRIVATE_KEY — following this verbatim raises "PERP_WALLET_ADDRESS_1 ... is required". The example module paths above (examples.rest_api.wallet_example, examples.websocket.market_monitoring) are also missing the perps/ segment → ModuleNotFoundError. Please align with .env.example and the actual example layout.

Comment thread tests/parity/README.md

## How it works

- [sign_ts.mjs](sign_ts.mjs) signs three v2.3.0 envelopes (Order, OrderCancel,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 Important — "three" should be five. sign_ts.mjs emits five vectors (order, order_sell, order_post_only, order_cancel, mass_cancel), but this README says three envelopes / "copy the three hex strings" — a maintainer regenerating would silently drop the sell + post-only parity vectors. (Separately, the OrdersGateway address in the test-vector section is the cronos address 0x5a0a…7ca5, while the vectors actually sign against the devnet1 address 0x7Ec8…3D4D.)

return True, required_margin(price_decimal, Decimal(qty), market_params.max_leverage)
except RECOVERABLE_EXC as e:
err = str(e).lower()
if "insufficient" in err or "margin" in err or "balance" in err:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 Important — retry decisions from substring-matching exception text are brittle. Classifying recoverability via "insufficient"/"margin"/"balance" in str(e) breaks when the server's wording changes (a "position would exceed initial margin requirement" reject misses the keywords → the level is abandoned with a single WARNING) and false-positives on any error whose body happens to contain "balance". Prefer branching on e.status / a structured error code. It's example code, but it's the pattern users copy.

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.

3 participants