client/asset/eth: handle swap fee rates below the network base fee#6
client/asset/eth: handle swap fee rates below the network base fee#6peterzen wants to merge 4 commits into
Conversation
The server-assigned swap fee rate becomes the transaction's gas fee cap verbatim. If the network's base fee exceeds it at broadcast time, the tx cannot be mined until the base fee recedes, and meanwhile occupies the nonce, blocking every subsequent transaction from the wallet until it is mined or replaced. Check the assigned rate against the current base fee before initiation and error instead of broadcasting, leaving the nonce unspent. Core retries the swap, which proceeds if the base fee recedes within the broadcast timeout. The already-initiated recovery path is unaffected. Redeem already handles this condition by raising its fee cap, funds permitting. Co-Authored-By: Claude Fable 5 <[email protected]>
Rather than refusing outright when the server-assigned swap fee rate is below the network's current base fee, attempt to raise the tx's gas fee cap to 2*baseFee, funds permitting, mirroring the existing rescue in Redeem. Under EIP-1559 the fee cap is not the fee paid, and the server's ValidateFeeRate only requires the cap to be at least the assigned rate, so a higher cap is protocol-legal. Refusal remains as a last resort when available balance cannot cover a minable cap. This also prepares for live (non-maximal) server fee rate assignment, where a fee spike between match time and broadcast time would otherwise strand honest traders. Co-Authored-By: Claude Fable 5 <[email protected]>
There was a problem hiding this comment.
Pull request overview
This PR improves EVM-family (ETH/Polygon) swap broadcasting reliability under EIP-1559 by preventing initiation transactions from being broadcast with a gas fee cap below the network base fee, and by “rescuing” the cap upward (funds permitting) to keep swaps minable.
Changes:
- Add swap fee-cap rescue logic to raise the swap tx gas fee cap to
2*baseFeewhen the server-assigned rate is below the current base fee, and refuse broadcast when a minable cap cannot be funded. - Update both ETH and token Swap paths to use
currentNetworkFeesbase fee + improved error messaging and minability checks. - Extend Swap tests to validate fee-cap rescue behavior and refusal when unfunded.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| client/asset/eth/eth.go | Adds fee-cap rescue + minability guard for swap initiations when base fee exceeds assigned cap. |
| client/asset/eth/eth_test.go | Adds assertions for rescued fee cap and refusal behavior; captures tx option fee/tip caps for verification. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| additionalFundsNeeded := (2 * baseFeeGwei * gasLimit) - feesReserved | ||
| if bal.Available > additionalFundsNeeded { | ||
| feeRateGwei = 2 * baseFeeGwei | ||
| } else { | ||
| feeRateGwei = (bal.Available + feesReserved) / gasLimit | ||
| } |
There was a problem hiding this comment.
Fixed in 0eede22: the rescue budget is now computed in big.Int (the base fee is provider-reported, so absurd values must not overflow the decision), with a zero-gasLimit guard before the division and an IsUint64 sanity check on the result.
| n.lastTxOptsMaxFeeRate = maxFeeRate | ||
| n.lastTxOptsTipRate = tipRate | ||
| txOpts := newTxOpts(ctx, n.addr, val, maxGas, maxFeeRate, dexeth.GweiToWei(2)) | ||
| txOpts.Nonce = big.NewInt(1) |
There was a problem hiding this comment.
Declined, with a comment added in 0eede22 explaining why: honoring the passed tipRate changes fee-derived decisions across existing fixtures tuned to the fixed 2 gwei tip (TestGaslessRedeem's submit/no-submit expectations flip). The new lastTxOptsTipRate capture field exposes the passed tip for assertions without perturbing unrelated tests, which is what this PR's assertions use.
Address review: the base fee is provider-reported, so compute the rescue budget in big.Int to keep absurd values from overflowing the decision, and guard the gasLimit division. Co-Authored-By: Claude Fable 5 <[email protected]>
The initial maxFeeRate value derived from swaps.FeeRate was never read now that the rescue result determines the fee cap; declare it at the point of use instead. Fixes the ineffassign CI failure. Co-Authored-By: Claude Fable 5 <[email protected]>
Prevents stuck EVM swap settlements when the network base fee exceeds the server-assigned fee rate (the tx's gas fee cap).
Two commits: the first refuses to broadcast an unminable swap tx, leaving the nonce unspent so core can retry. The second improves on refusal: raise the fee cap to 2*baseFee funds permitting (the same rescue Redeem already uses; a higher cap is protocol-legal since ValidateFeeRate only enforces a floor), refusing only when balance cannot cover a minable cap. Applies to all EVM-family wallets (eth, polygon).
This is also the client-side prerequisite for live server fee-rate assignment (see companion server PR).