Skip to content

Commit 3ca4c04

Browse files
committed
eth: Use user set gas limit.
1 parent 7aac94c commit 3ca4c04

File tree

2 files changed

+98
-101
lines changed

2 files changed

+98
-101
lines changed

client/asset/eth/eth.go

Lines changed: 81 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,8 +1969,13 @@ func (w *assetWallet) PreRedeem(req *asset.PreRedeemForm) (*asset.PreRedeem, err
19691969
return nil, err
19701970
}
19711971

1972-
bestCase := nRedeem * req.FeeSuggestion
1973-
worstCase := oneRedeem * req.Lots * req.FeeSuggestion
1972+
feeRate, _, _, err := w.feeRate(w.ctx, req.FeeSuggestion)
1973+
if err != nil {
1974+
return nil, fmt.Errorf("unable to get fee rate: %v", err)
1975+
}
1976+
1977+
bestCase := nRedeem * feeRate
1978+
worstCase := oneRedeem * req.Lots * feeRate
19741979
userOpRequired := false
19751980

19761981
w.bundlerMtx.RLock()
@@ -2000,7 +2005,11 @@ func (w *assetWallet) SingleLotRedeemFees(assetVer uint32, feeSuggestion uint64)
20002005
if g == nil {
20012006
return 0, fmt.Errorf("no gases known for %d, constract version %d", w.assetID, contractVersion(assetVer))
20022007
}
2003-
return g.Redeem * feeSuggestion, nil
2008+
feeRate, _, _, err := w.feeRate(w.ctx, feeSuggestion)
2009+
if err != nil {
2010+
return 0, fmt.Errorf("unable to get fee rate: %v", err)
2011+
}
2012+
return g.Redeem * feeRate, nil
20042013
}
20052014

20062015
// coin implements the asset.Coin interface for ETH
@@ -2069,29 +2078,28 @@ func (w *ETHWallet) FundOrder(ord *asset.Order) (asset.Coins, []dex.Bytes, uint6
20692078
dex.BipIDSymbol(w.assetID), ord.MaxFeeRate, dexeth.MinGasTipCap)
20702079
}
20712080

2072-
if w.gasFeeLimit() < ord.MaxFeeRate {
2073-
return nil, nil, 0, fmt.Errorf(
2074-
"%v: server's max fee rate %v higher than configured fee rate limit %v",
2075-
dex.BipIDSymbol(w.assetID), ord.MaxFeeRate, w.gasFeeLimit())
2081+
feeRate, _, _, err := w.feeRate(w.ctx, ord.MaxFeeRate)
2082+
if err != nil {
2083+
return nil, nil, 0, fmt.Errorf("unable to get fee rate: %v", err)
20762084
}
20772085

20782086
contractVer := contractVersion(ord.AssetVersion)
20792087

20802088
g, err := w.initGasEstimate(int(ord.MaxSwapCount), contractVer,
2081-
ord.RedeemVersion, ord.RedeemAssetID, ord.MaxFeeRate)
2089+
ord.RedeemVersion, ord.RedeemAssetID, feeRate)
20822090
if err != nil {
20832091
return nil, nil, 0, fmt.Errorf("error estimating swap gas: %v", err)
20842092
}
20852093

2086-
ethToLock := ord.MaxFeeRate*g.Swap*ord.MaxSwapCount + ord.Value
2094+
ethToLock := feeRate*g.Swap*ord.MaxSwapCount + ord.Value
20872095
// Note: In a future refactor, we could lock the redemption funds here too
20882096
// and signal to the user so that they don't call `RedeemN`. This has the
20892097
// same net effect, but avoids a lockFunds -> unlockFunds for us and likely
20902098
// some work for the caller as well. We can't just always do it that way and
20912099
// remove RedeemN, since we can't guarantee that the redemption asset is in
20922100
// our fee-family. though it could still be an AccountRedeemer.
20932101
w.log.Debugf("Locking %s to swap %s in up to %d swaps at a fee rate of %d gwei/gas using up to %d gas per swap",
2094-
w.amtString(ethToLock), w.amtString(ord.Value), ord.MaxSwapCount, ord.MaxFeeRate, g.Swap)
2102+
w.amtString(ethToLock), w.amtString(ord.Value), ord.MaxSwapCount, feeRate, g.Swap)
20952103

20962104
coin := w.createFundingCoin(ethToLock)
20972105

@@ -2109,10 +2117,9 @@ func (w *TokenWallet) FundOrder(ord *asset.Order) (asset.Coins, []dex.Bytes, uin
21092117
dex.BipIDSymbol(w.assetID), ord.MaxFeeRate, dexeth.MinGasTipCap)
21102118
}
21112119

2112-
if w.gasFeeLimit() < ord.MaxFeeRate {
2113-
return nil, nil, 0, fmt.Errorf(
2114-
"%v: server's max fee rate %v higher than configured fee rate limit %v",
2115-
dex.BipIDSymbol(w.assetID), ord.MaxFeeRate, w.gasFeeLimit())
2120+
feeRate, _, _, err := w.feeRate(w.ctx, ord.MaxFeeRate)
2121+
if err != nil {
2122+
return nil, nil, 0, fmt.Errorf("unable to get fee rate: %v", err)
21162123
}
21172124

21182125
approvalStatus, err := w.swapContractApprovalStatus(ord.AssetVersion)
@@ -2130,12 +2137,12 @@ func (w *TokenWallet) FundOrder(ord *asset.Order) (asset.Coins, []dex.Bytes, uin
21302137
}
21312138

21322139
g, err := w.initGasEstimate(int(ord.MaxSwapCount), contractVersion(ord.AssetVersion),
2133-
ord.RedeemVersion, ord.RedeemAssetID, ord.MaxFeeRate)
2140+
ord.RedeemVersion, ord.RedeemAssetID, feeRate)
21342141
if err != nil {
21352142
return nil, nil, 0, fmt.Errorf("error estimating swap gas: %v", err)
21362143
}
21372144

2138-
ethToLock := ord.MaxFeeRate * g.Swap * ord.MaxSwapCount
2145+
ethToLock := feeRate * g.Swap * ord.MaxSwapCount
21392146
var success bool
21402147
if err = w.lockFunds(ord.Value, initiationReserve); err != nil {
21412148
return nil, nil, 0, fmt.Errorf("error locking token funds: %v", err)
@@ -2147,7 +2154,7 @@ func (w *TokenWallet) FundOrder(ord *asset.Order) (asset.Coins, []dex.Bytes, uin
21472154
}()
21482155

21492156
w.log.Debugf("Locking %s to swap %s in up to %d swaps at a fee rate of %d gwei/gas using up to %d gas per swap",
2150-
w.parent.amtString(ethToLock), w.amtString(ord.Value), ord.MaxSwapCount, ord.MaxFeeRate, g.Swap)
2157+
w.parent.amtString(ethToLock), w.amtString(ord.Value), ord.MaxSwapCount, feeRate, g.Swap)
21512158
if err := w.parent.lockFunds(ethToLock, initiationReserve); err != nil {
21522159
return nil, nil, 0, err
21532160
}
@@ -2161,21 +2168,20 @@ func (w *TokenWallet) FundOrder(ord *asset.Order) (asset.Coins, []dex.Bytes, uin
21612168
// FundMultiOrder funds multiple orders in one shot. No special handling is
21622169
// required for ETH as ETH does not over-lock during funding.
21632170
func (w *ETHWallet) FundMultiOrder(ord *asset.MultiOrder, maxLock uint64) ([]asset.Coins, [][]dex.Bytes, uint64, error) {
2164-
if w.gasFeeLimit() < ord.MaxFeeRate {
2165-
return nil, nil, 0, fmt.Errorf(
2166-
"%v: server's max fee rate %v higher than configured fee rate limit %v",
2167-
dex.BipIDSymbol(w.assetID), ord.MaxFeeRate, w.gasFeeLimit())
2171+
feeRate, _, _, err := w.feeRate(w.ctx, ord.MaxFeeRate)
2172+
if err != nil {
2173+
return nil, nil, 0, fmt.Errorf("unable to get fee rate: %v", err)
21682174
}
21692175

2170-
g, err := w.initGasEstimate(1, ord.AssetVersion, ord.RedeemVersion, ord.RedeemAssetID, ord.MaxFeeRate)
2176+
g, err := w.initGasEstimate(1, ord.AssetVersion, ord.RedeemVersion, ord.RedeemAssetID, feeRate)
21712177
if err != nil {
21722178
return nil, nil, 0, fmt.Errorf("error estimating swap gas: %v", err)
21732179
}
21742180

21752181
var totalToLock uint64
21762182
allCoins := make([]asset.Coins, 0, len(ord.Values))
21772183
for _, value := range ord.Values {
2178-
toLock := ord.MaxFeeRate*g.Swap*value.MaxSwapCount + value.Value
2184+
toLock := feeRate*g.Swap*value.MaxSwapCount + value.Value
21792185
allCoins = append(allCoins, asset.Coins{w.createFundingCoin(toLock)})
21802186
totalToLock += toLock
21812187
}
@@ -2199,10 +2205,9 @@ func (w *ETHWallet) FundMultiOrder(ord *asset.MultiOrder, maxLock uint64) ([]ass
21992205
// FundMultiOrder funds multiple orders in one shot. No special handling is
22002206
// required for ETH as ETH does not over-lock during funding.
22012207
func (w *TokenWallet) FundMultiOrder(ord *asset.MultiOrder, maxLock uint64) ([]asset.Coins, [][]dex.Bytes, uint64, error) {
2202-
if w.gasFeeLimit() < ord.MaxFeeRate {
2203-
return nil, nil, 0, fmt.Errorf(
2204-
"%v: server's max fee rate %v higher than configured fee rate limit %v",
2205-
dex.BipIDSymbol(w.assetID), ord.MaxFeeRate, w.gasFeeLimit())
2208+
feeRate, _, _, err := w.feeRate(w.ctx, ord.MaxFeeRate)
2209+
if err != nil {
2210+
return nil, nil, 0, fmt.Errorf("unable to get fee rate: %v", err)
22062211
}
22072212

22082213
approvalStatus, err := w.swapContractApprovalStatus(ord.AssetVersion)
@@ -2220,15 +2225,15 @@ func (w *TokenWallet) FundMultiOrder(ord *asset.MultiOrder, maxLock uint64) ([]a
22202225
}
22212226

22222227
g, err := w.initGasEstimate(1, ord.AssetVersion,
2223-
ord.RedeemVersion, ord.RedeemAssetID, ord.MaxFeeRate)
2228+
ord.RedeemVersion, ord.RedeemAssetID, feeRate)
22242229
if err != nil {
22252230
return nil, nil, 0, fmt.Errorf("error estimating swap gas: %v", err)
22262231
}
22272232

22282233
var totalETHToLock, totalTokenToLock uint64
22292234
allCoins := make([]asset.Coins, 0, len(ord.Values))
22302235
for _, value := range ord.Values {
2231-
ethToLock := ord.MaxFeeRate * g.Swap * value.MaxSwapCount
2236+
ethToLock := feeRate * g.Swap * value.MaxSwapCount
22322237
tokenToLock := value.Value
22332238
allCoins = append(allCoins, asset.Coins{w.createTokenFundingCoin(tokenToLock, ethToLock)})
22342239
totalETHToLock += ethToLock
@@ -2561,8 +2566,9 @@ var _ asset.Receipt = (*swapReceipt)(nil)
25612566
// max fees that will possibly be used, since in ethereum with EIP-1559 we cannot
25622567
// know exactly how much fees will be used.
25632568
func (w *ETHWallet) Swap(swaps *asset.Swaps) ([]asset.Receipt, asset.Coin, uint64, error) {
2564-
if swaps.FeeRate == 0 {
2565-
return nil, nil, 0, fmt.Errorf("cannot send swap with with zero fee rate")
2569+
feeRate, maxFeeRate, tipRate, err := w.feeRate(w.ctx, swaps.FeeRate)
2570+
if err != nil {
2571+
return nil, nil, 0, fmt.Errorf("unable to get fee rate: %v", err)
25662572
}
25672573

25682574
fail := func(s string, a ...any) ([]asset.Receipt, asset.Coin, uint64, error) {
@@ -2585,20 +2591,20 @@ func (w *ETHWallet) Swap(swaps *asset.Swaps) ([]asset.Receipt, asset.Coin, uint6
25852591

25862592
contractVer := contractVersion(swaps.AssetVersion)
25872593
n := len(swaps.Contracts)
2588-
oneSwap, nSwap, err := w.swapGas(n, contractVer, swaps.FeeRate)
2594+
oneSwap, nSwap, err := w.swapGas(n, contractVer, feeRate)
25892595
if err != nil {
25902596
return fail("error getting gas fees: %v", err)
25912597
}
25922598
gasLimit := oneSwap * uint64(n) // naive unbatched, higher but not realistic
2593-
fees := gasLimit * swaps.FeeRate
2599+
fees := gasLimit * feeRate
25942600
if swapVal+fees > reservedVal {
25952601
if n == 1 {
25962602
return fail("unfunded swap: %d < %d", reservedVal, swapVal+fees)
25972603
}
25982604
w.log.Warnf("Unexpectedly low reserves for %d swaps: %d < %d", n, reservedVal, swapVal+fees)
25992605
// Since this is a batch swap, attempt to use the realistic limits.
26002606
gasLimit = nSwap
2601-
fees = gasLimit * swaps.FeeRate
2607+
fees = gasLimit * feeRate
26022608
if swapVal+fees > reservedVal {
26032609
// If the live gas estimate is giving us an unrealistically high
26042610
// value, we're in trouble, so we might consider a third fallback
@@ -2611,13 +2617,8 @@ func (w *ETHWallet) Swap(swaps *asset.Swaps) ([]asset.Receipt, asset.Coin, uint6
26112617
}
26122618
}
26132619

2614-
maxFeeRate := dexeth.GweiToWei(swaps.FeeRate)
2615-
_, tipRate, err := w.currentNetworkFees(w.ctx)
2616-
if err != nil {
2617-
return fail("Swap: failed to get network tip cap: %w", err)
2618-
}
2619-
2620-
tx, err := w.initiate(w.ctx, w.assetID, swaps.Contracts, gasLimit, maxFeeRate, tipRate, contractVer)
2620+
maxFeeRateBig := dexeth.GweiToWei(maxFeeRate)
2621+
tx, err := w.initiate(w.ctx, w.assetID, swaps.Contracts, gasLimit, maxFeeRateBig, tipRate, contractVer)
26212622
if err != nil {
26222623
return fail("Swap: initiate error: %w", err)
26232624
}
@@ -2670,8 +2671,9 @@ func acToLocator(contractVer uint32, swap *asset.Contract, evmValue *big.Int, fr
26702671
// max fees that will possibly be used, since in ethereum with EIP-1559 we cannot
26712672
// know exactly how much fees will be used.
26722673
func (w *TokenWallet) Swap(swaps *asset.Swaps) ([]asset.Receipt, asset.Coin, uint64, error) {
2673-
if swaps.FeeRate == 0 {
2674-
return nil, nil, 0, fmt.Errorf("cannot send swap with with zero fee rate")
2674+
feeRate, maxFeeRate, tipRate, err := w.feeRate(w.ctx, swaps.FeeRate)
2675+
if err != nil {
2676+
return nil, nil, 0, fmt.Errorf("unable to get fee rate: %v", err)
26752677
}
26762678

26772679
fail := func(s string, a ...any) ([]asset.Receipt, asset.Coin, uint64, error) {
@@ -2699,37 +2701,32 @@ func (w *TokenWallet) Swap(swaps *asset.Swaps) ([]asset.Receipt, asset.Coin, uin
26992701

27002702
n := len(swaps.Contracts)
27012703
contractVer := contractVersion(swaps.AssetVersion)
2702-
oneSwap, nSwap, err := w.swapGas(n, contractVer, swaps.FeeRate)
2704+
oneSwap, nSwap, err := w.swapGas(n, contractVer, feeRate)
27032705
if err != nil {
27042706
return fail("error getting gas fees: %v", err)
27052707
}
27062708

27072709
gasLimit := oneSwap * uint64(n)
2708-
fees := gasLimit * swaps.FeeRate
2710+
fees := gasLimit * feeRate
27092711
if fees > reservedParent {
27102712
if n == 1 {
27112713
return fail("unfunded token swap fees: %d < %d", reservedParent, fees)
27122714
}
27132715
// Since this is a batch swap, attempt to use the realistic limits.
27142716
w.log.Warnf("Unexpectedly low reserves for %d swaps: %d < %d", n, reservedVal, swapVal+fees)
27152717
gasLimit = nSwap
2716-
fees = gasLimit * swaps.FeeRate
2718+
fees = gasLimit * feeRate
27172719
if fees > reservedParent {
27182720
return fail("unfunded token swap fees: %d < %d", reservedParent, fees)
27192721
} // See (*ETHWallet).Swap comments for a third option.
27202722
}
27212723

2722-
maxFeeRate := dexeth.GweiToWei(swaps.FeeRate)
2723-
_, tipRate, err := w.currentNetworkFees(w.ctx)
2724-
if err != nil {
2725-
return fail("Swap: failed to get network tip cap: %w", err)
2726-
}
2727-
2724+
maxFeeRateBig := dexeth.GweiToWei(maxFeeRate)
27282725
if w.netToken.SwapContracts[swaps.AssetVersion] == nil {
27292726
return fail("unable to find contract address for asset %d contract version %d", w.assetID, swaps.AssetVersion)
27302727
}
27312728

2732-
tx, err := w.initiate(w.ctx, w.assetID, swaps.Contracts, gasLimit, maxFeeRate, tipRate, contractVer)
2729+
tx, err := w.initiate(w.ctx, w.assetID, swaps.Contracts, gasLimit, maxFeeRateBig, tipRate, contractVer)
27332730
if err != nil {
27342731
return fail("Swap: initiate error: %w", err)
27352732
}
@@ -3088,17 +3085,6 @@ func (w *assetWallet) Redeem(form *asset.RedeemForm, feeWallet *assetWallet, non
30883085
return fail(fmt.Errorf("no gas table"))
30893086
}
30903087

3091-
if feeWallet == nil {
3092-
feeWallet = w
3093-
}
3094-
bal, err := feeWallet.Balance()
3095-
if err != nil {
3096-
return fail(fmt.Errorf("error getting balance in excessive gas fee recovery: %v", err))
3097-
}
3098-
3099-
gasLimit, gasFeeCap := g.Redeem*n, form.FeeSuggestion
3100-
originalFundsReserved := gasLimit * gasFeeCap
3101-
31023088
/* We could get a gas estimate via RPC, but this will reveal the secret key
31033089
before submitting the redeem transaction. This is not OK for maker.
31043090
Disable for now.
@@ -3125,25 +3111,12 @@ func (w *assetWallet) Redeem(form *asset.RedeemForm, feeWallet *assetWallet, non
31253111
}
31263112
*/
31273113

3128-
// If the base fee is higher than the FeeSuggestion we attempt to increase
3129-
// the gasFeeCap to 2*baseFee. If we don't have enough funds, we use the
3130-
// funds we have available.
3131-
baseFee, tipRate, err := w.currentNetworkFees(w.ctx)
3114+
feeRate, maxFeeRate, tipRate, err := w.feeRate(w.ctx, form.FeeSuggestion)
31323115
if err != nil {
3133-
return fail(fmt.Errorf("Error getting net fee state: %w", err))
3134-
}
3135-
baseFeeGwei := dexeth.WeiToGweiCeil(baseFee)
3136-
if baseFeeGwei > form.FeeSuggestion {
3137-
additionalFundsNeeded := (2 * baseFeeGwei * gasLimit) - originalFundsReserved
3138-
if bal.Available > additionalFundsNeeded {
3139-
gasFeeCap = 2 * baseFeeGwei
3140-
} else {
3141-
gasFeeCap = (bal.Available + originalFundsReserved) / gasLimit
3142-
}
3143-
w.log.Warnf("base fee %d > server max fee rate %d. using %d as gas fee cap for redemption", baseFeeGwei, form.FeeSuggestion, gasFeeCap)
3116+
return fail(fmt.Errorf("unable to get fee rate: %v", err))
31443117
}
31453118

3146-
tx, err := w.redeem(w.ctx, form.Redemptions, gasFeeCap, tipRate, gasLimit, contractVer)
3119+
tx, err := w.redeem(w.ctx, form.Redemptions, maxFeeRate, tipRate, g.Redeem*n, contractVer)
31473120
if err != nil {
31483121
return fail(fmt.Errorf("Redeem: redeem error: %w", err))
31493122
}
@@ -3162,7 +3135,7 @@ func (w *assetWallet) Redeem(form *asset.RedeemForm, feeWallet *assetWallet, non
31623135

31633136
// This is still a fee estimate. The actual gas cost will be returned in the
31643137
// receipt.
3165-
fees := g.RedeemN(len(form.Redemptions)) * form.FeeSuggestion
3138+
fees := g.RedeemN(len(form.Redemptions)) * feeRate
31663139
return txs, outputCoin, fees, nil
31673140
}
31683141

@@ -4498,13 +4471,17 @@ func (w *assetWallet) Refund(_, contract dex.Bytes, feeRate uint64) (dex.Bytes,
44984471
return nil, fmt.Errorf("Refund: swap with locator %x is not refundable", locator)
44994472
}
45004473

4501-
maxFeeRate := dexeth.GweiToWei(feeRate)
4474+
maxFeeRate := w.gasFeeLimit()
4475+
if feeRate > maxFeeRate {
4476+
w.log.Warnf("Refund fee rate higher than max fee. %d > %d", feeRate, maxFeeRate)
4477+
}
4478+
maxFeeRateBig := dexeth.GweiToWei(maxFeeRate)
45024479
_, tipRate, err := w.currentNetworkFees(w.ctx)
45034480
if err != nil {
45044481
return nil, fmt.Errorf("Refund: failed to get network tip cap: %w", err)
45054482
}
45064483

4507-
tx, err := w.refund(locator, w.atomize(vector.Value), maxFeeRate, tipRate, contractVer)
4484+
tx, err := w.refund(locator, w.atomize(vector.Value), maxFeeRateBig, tipRate, contractVer)
45084485
if err != nil {
45094486
return nil, fmt.Errorf("Refund: failed to call refund: %w", err)
45104487
}
@@ -5123,6 +5100,27 @@ func (w *baseWallet) currentBaseFee(ctx context.Context) (*big.Int, error) {
51235100
return base, nil
51245101
}
51255102

5103+
// feeRate returns the higher of suggested fee rate and the current on chain fee
5104+
// rate and caps with the maxFeeRate.
5105+
func (w *baseWallet) feeRate(ctx context.Context, suggestedFeeRate uint64) (feeRate, maxFeeRate uint64, tipRate *big.Int, err error) {
5106+
maxFeeRate = w.gasFeeLimit()
5107+
if maxFeeRate < suggestedFeeRate {
5108+
return 0, 0, nil, fmt.Errorf(
5109+
"server's max fee rate %v higher than configured fee rate limit %v",
5110+
suggestedFeeRate, maxFeeRate)
5111+
}
5112+
var estimate uint64
5113+
liveRateBig, tipRate, err := w.recommendedMaxFeeRate(ctx)
5114+
if err != nil {
5115+
return 0, 0, nil, fmt.Errorf("unable to get recommended fee rate: %v", err)
5116+
}
5117+
estimate, err = dexeth.WeiToGweiSafe(liveRateBig)
5118+
if err != nil {
5119+
return 0, 0, nil, fmt.Errorf("unable to convert to gwei: %v", err)
5120+
}
5121+
return min(max(estimate, suggestedFeeRate), maxFeeRate), maxFeeRate, tipRate, nil
5122+
}
5123+
51265124
// currentNetworkFees give the current base fee rate (from the best header),
51275125
// and recommended tip cap.
51285126
func (w *baseWallet) currentNetworkFees(ctx context.Context) (baseRate, tipRate *big.Int, err error) {

0 commit comments

Comments
 (0)