Repository navigation
fix(managed-wallet): answer 400 when the chain refuses a message as invalid in simulation - #4544
Conversation
…nvalid in simulation A message the chain refuses at validation reaches gas simulation as its own error, unwrapped, so it never says "failed to execute message" and was answered with a 500. Simulate rejections whose description calls the transaction invalid now raise MessageExecutionFailedError too. Sequence mismatches and expired simulations keep their current answers. Refs CON-1343
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4544 +/- ##
==========================================
+ Coverage 94.07% 94.26% +0.19%
==========================================
Files 1773 1697 -76
Lines 50951 48785 -2166
Branches 12442 11994 -448
==========================================
- Hits 47934 45989 -1945
+ Misses 2707 2501 -206
+ Partials 310 295 -15
*This pull request uses carry forward flags. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
|
This run hit its 1h time limit while still working. Give runs longer with
|
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing: 3
✨ Finishing Touches
Comment |
Ante refusals such as an unordered ttl the node's clock rejects end in a generic ": invalid request", and a recovered chain panic mentions an invalid memory address. Matching "invalid" anywhere turned those node-side failures into 400s, so the match is now anchored to the start of the description. Refs CON-1343
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Re-reviewed the delta since the previously reviewed d5fd3e0 — the single new commit 7b52d43, which tightens the invalid-message match to descriptions that open with "invalid".
- Anchored
INVALID_MESSAGE_REto the start of the description — a Simulate rejection now classifies asMessageExecutionFailedErroronly when itsdescopens withinvalid(desc = invalid\b). The three incident wordings stay 400 (invalid deposit,invalid pubkey value,Invalid groupsvia the/iflag), while ante refusals that merely end in a generic: invalid request(an unordered TTL past the node's 10-minute cap,… has already passed) and recovered chain panics keep answering 500. This supersedes the earlier optional suggestion to boundUNORDERED_TX_TTL_MSinenv.config.tsby fixing the misclassification class itself. - Added negative tests for both exclusion cases — a new
it.eachasserts the unordered-TTL and recovered-panic refusals stay unclassified with the chain's wording preserved and a single simulate attempt (no retry); the node-level refusal test also gained a no-retry assertion.
The fixture wording was verified against cosmos-sdk v0.53.4 (x/auth/ante/sigverify.go): verifyUnorderedNonce raises Wrapf(ErrInvalidRequest, "unordered tx ttl exceeds %s", …), which renders detail-first and ends : invalid request, so the anchor is the right discriminator; the ErrTxDecode/ErrUnauthorized wraps that do open with "invalid" are unreachable for cosmjs-built proto txs. Full tx-signer battery green locally: 179 tests (160 unit + 19 functional), npx tsc --noEmit, lint and prettier clean.
GLM-5.3 | 𝕏

Why
POST /v1/txanswered 500 five times on 2026-10-21 for transactions whose gas simulation the chain refused at message validation:The chain runs message validation before the ante handler and returns the error as is, so the log never says
failed to execute message. tx-signer only answers 400 when it does (#4052), so these went out as 500. console-api relayed them as "Service temporarily unavailable" and both 5xx alerts fired.Fixes CON-1343
What
MessageExecutionFailedErrorwhen the Simulate rejection's description opens with "invalid". The error handler already answers that error with 400 and the chain's message.: invalid request) and recovered chain panics (recovered: runtime error: invalid memory address ...) stay 500./v1/txalready relays a tx-signer 400 for caller-supplied messages (fix(managed-wallet): return the signer's 400 or 403 to the /v1/tx caller instead of a 500 #4057), and messages console builds itself still fail as 500.Testing
invalid depositand checks for a 400 with nothing broadcast.npm test, lint and tsc pass in apps/tx-signer. Stryker kills 5 of 5 mutants on the changed lines.Summary by CodeRabbit