Repository navigation
fix(mev): send BlockRazor its own method on every submit path, not just SendBundleV2 - #229
datluongductuan wants to merge 1 commit into
Conversation
…st SendBundleV2 #227 taught SendBundleV2 that BlockRazor's free RPC serves eth_sendMevBundle, but SendBundle and SendBundleHex still hardcoded eth_sendBundle. The two entry points therefore disagreed about the protocol: a caller on the plain path reached a method bsc.blockrazor.xyz does not implement, so the bundle never lands and the send itself looks fine — there is no error to see. That is not hypothetical. dexdex-arb's broadcaster calls SendBundle, so wiring BlockRazor there against the current library would have submitted the wrong method from the first bundle. The choice moves into submitBundleMethod() and is applied at the three submit entry points. Deliberately NOT inside sendBundle: CancelBundle and SimulateBundle pass a method of their own (eth_sendBundle for a cancel, eth_callBundle for a simulation), and rewriting those would turn a simulation into a submission. Tests pin the method on both plain paths, for BlockRazor and for a control sender, and pin that eth_callBundle survives. Verified by mutation: flattening submitBundleMethod to the constant fails the new SendBundleHex case and the existing SendBundleV2 one, so the refactor is covered from both directions. Not addressed here: SendBundle still omits the 48spSign body field that SendBundleV2 sets for 48Club, because Sign48SPMember needs the parsed transactions and SendBundleHex has only their hex. A 48Club bundle sent via SendBundle is a valid anonymous bundle — it just forgoes Soul Point priority. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Closing — superseded by a fix on the consumer side.
if sender.GetSenderType() == mev.BundleSenderTypeBlockRazor {
return sender.SendBundleV2(ctx, mev.SendBundleV2Request{UUID: bUUID, BlockNumber: &blockNum}, bundle...)
}
return sender.SendBundle(ctx, bUUID, blockNum, bundle...)Verified end-to-end against stock v0.11.32 through the real That unblocks BSC now rather than waiting on a release here, and keeps the blast radius to one service instead of every tradinglib consumer. Worth noting the underlying asymmetry is still there: |
Found while wiring the BSC builders into dexdex-arb, which is what makes it
concrete rather than theoretical.
The bug
#227 taught
SendBundleV2that BlockRazor's free RPC serveseth_sendMevBundle.SendBundleandSendBundleHexkept hardcodingeth_sendBundle:So the two entry points disagreed about the protocol. A caller on the plain path
reaches a method
bsc.blockrazor.xyzdoes not implement — the bundle neverlands and the send looks fine. There is no error to see, which is the worst
shape this class of bug comes in.
This is not hypothetical: dexdex-arb's broadcaster calls
SendBundle(
internal/executor/broadcaster/broadcaster.go:288). Wiring BlockRazor thereagainst the current library would have submitted the wrong method from the very
first bundle, and it would have looked healthy.
The fix
The choice moves into
submitBundleMethod()and is applied at the three submitentry points —
SendBundle,SendBundleHex,SendBundleV2.Deliberately not inside
sendBundle. Two of its callers pass a method oftheir own:
CancelBundleeth_sendBundleSimulateBundleeth_callBundlePushing the swap one level down would have been smaller and wrong.
Tests
The method is pinned on both plain paths, for BlockRazor and for a control
sender, plus a case that
eth_callBundlesurvives.Verified by mutation rather than assumed — flattening
submitBundleMethodto theconstant fails:
The existing #227 test failing too is the useful half: it shows the refactor did
not quietly change the V2 path it was meant to preserve.
go test ./pkg/mev/...30 passed.golangci-lint --new-from-rev=origin/mainclean (the 7 pre-existing issues in this package are untouched).
Not addressed here
SendBundlestill omits the48spSignbody field thatSendBundleV2sets for48Club:
Sign48SPMemberneeds the parsed transactions, andSendBundleHexhasonly their hex. A 48Club bundle sent via
SendBundleis a valid anonymousbundle — it just forgoes Soul Point priority. Worth a follow-up, not a
correctness break.
🤖 Generated with Claude Code