feat(client): add collateral return plan/execute to secure clients - #200
Merged
Conversation
cesarenaldi
reviewed
Jul 24, 2026
cesarenaldi
reviewed
Jul 24, 2026
cesarenaldi
reviewed
Jul 24, 2026
…havior - Rename the plan model to CollateralReturnPlanResponse with the ts-sdk field set: wire names (starting_pusd, net_pusd_out, final_pusd, required_pusd_input), restored operation_count, estimated_cost, and candidate_position_ids, and ts-matching required fields (only position_summary stays defaulted). - Apply the 120s request timeout to submit as well as plan; submit re-validation also recomputes wallet state server-side. - Drop CollateralReturnPlanRejectedError and the client-side empty-plan gate: stale and empty plans surface the service rejection as RequestRejectedError, matching ts-sdk. - Share one gasless submit retry helper between prepare_gasless_transaction and collateral return execution instead of four copies of the loop. - Move the decimal-string validators to a shared models module under public names; e6 amounts serialize back to base-unit strings in JSON mode so dumped plans re-validate to the same amounts, and signed amounts are rejected. - Narrow client execute return types to the gasless handles. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0c13450. Configure here.
Live plan assertions keep only service semantics the model cannot check (wallet, chain, router target, hash format); type re-assertions, the wire-exponent check, and empty-plan restatements are removed. The empty-plan scenario now mirrors ts-sdk: skip on inventory, assert no operations, expect the service rejection. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Payload builders return RelayerEnvelope and the submit functions require it, so arbitrary dicts cannot reach a submit endpoint without going through a builder. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cesarenaldi
approved these changes
Jul 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Adds Collateral Return support (DEV-445): a combos Protocol V2 position-lifecycle workflow that returns idle collateral to the wallet.
Sync
Async
Available on both
SecureClientandAsyncSecureClient(async is identical withawait). Supports Deposit Wallet, Safe, and Proxy accounts; EOA-bound clients are rejected before anything is planned or signed.What's included
CollateralReturnPlan— an inspectable execution artifact:Decimalcollateral amounts,position_summarywith consumed/created positions, and forward-compatible operation kinds (known kinds coerce toCollateralReturnOperationKind, unknown kinds parse as plain strings).MissingTradingApprovalsErrorbefore any signature; no approval transactions run implicitly. Stale plans raiseCollateralReturnPlanRejectedError(never retried; recovery is a fresh plan), while transient submission errors re-sign with a fresh nonce.build_signed_*_payloadhelpers reused by the existing gasless path; transports gained an optional per-request timeout so only the plan call waits up to 2 minutes.Tests
Note
Medium Risk
New on-chain execution path via signed router calls and relayer envelopes; mistakes in plan validation or signing could submit wrong transactions, though client-side wallet/chain checks and non-retry on 409 mitigate stale-plan risk.
Overview
Adds collateral return to sync and async secure clients:
plan_collateral_return()calls the combos collateral-return service (120s read timeout) and returns a typedCollateralReturnPlanResponse;execute_collateral_return_plan(plan=...)signs the plan’srouter_calland submits it to/v1/collateral-return/submitas a gasless transaction. Deposit Wallet, Safe, and Proxy are supported; EOAs are rejected up front; execution needs a Builder or Relayer API key and validates wallet/chain against the plan.Wires a new
combostransport (collateral_return_urlonEnvironment), exports collateral-return models and shared e6 decimal validators, and refactors gasless signing into reusablebuild_signed_*_payloadhelpers plussubmit_gasless_with_retry(collateral submit uses combos, not the relayer/submit).RelayerEnvelopeNewType guards relayer payloads;post_jsonaccepts an optional per-request timeout.Reviewed by Cursor Bugbot for commit 6b4fa14. Bugbot is set up for automated code reviews on this repo. Configure here.