Repository navigation
Conversation
The bid loop signs every plan with the gas estimate cached at evaluation, which expired after CACHE_EXPIRY_MS while slow place_bid calls were still going out, so the later plans never bid. The loop now pins the order in CacheService: its entries are aged as of the pin until the queued task settles, and entries already expired when the loop starts stay expired.
This branch has not been deployed
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.
What this does
IntentFiller.executeOrdersends one bid per cachedBidPlan, in turn, and every bid is signed byContractInteractionService.prepareBidUserOpwith the gas estimateestimateGasFillPostcached at evaluation.CacheServiceentries expire afterCACHE_EXPIRY_MS(60 s). When Hyperbridge holds eachplace_bidin its pool for 20 s or more, the loop outlives the cache, and the later plans fail withNo cached gas estimate found for order <id>.EventMonitordrops repeat order ids, so those legs never get a bid.Seen in the simplex testnet swaps run https://github.com/polytope-labs/hyperbridge/actions/runs/39275362211 (job 118147728951), scenario
multi-leg-same-input: TIMEOUT with 2 fills, 4No cached gas estimateerrors.Behavior
CacheService.pinOrder(orderId)returns the release, whichexecuteOrdercalls in a.finallyon the queued task, however the task ends.fill-path-safety.test.tsstubs the cache by hand, so its two stubs gainpinOrder. The newsrc/tests/core/bid-loop-cache-expiry.test.tsis added totest:unit, which did not coversrc/tests/corebefore. Note:docs/ai/changelog/2026-10-20-bid-loop-outlives-the-evaluation-cache.md.The open stack #1410 → #1414 → #1421 → #1422 rewrites this loop. To keep the conflict small, the
filler.tschange is about 10 lines and does not re-indent the loop. That stack's rewrittenfill-path-safety.test.tsstubs will needpinOrder: () => () => {}too.Validation
bid-loop-cache-expiry.test.tsruns three plans through the realprepareBidUserOp, with each submission takingCACHE_EXPIRY_MS + 1 s. All three are signed and executed, and the pin is released afterwards. On main only the first is signed. A second case checks that an evaluation which expired before the loop sends nothing.pnpm --filter @hyperbridge/simplex test:unit: 263 passed.test:filler: 59 passed, 5 skipped.src/tests/coreplusbid-budget,bid-call-gasandbid-gas-estimate: 138 passed.lint: no errors.tsc: nothing reported in the touched files.🤖 Generated with Claude Code