|
6 | 6 | "math/big" |
7 | 7 | "strings" |
8 | 8 |
|
| 9 | + "github.com/ethereum/go-ethereum" |
9 | 10 | "github.com/ethereum/go-ethereum/accounts/abi" |
10 | 11 | "github.com/ethereum/go-ethereum/common" |
11 | 12 |
|
@@ -216,6 +217,70 @@ func (w *chainWriter) GetFeeComponents(ctx context.Context) (*commontypes.ChainF |
216 | 217 | }, nil |
217 | 218 | } |
218 | 219 |
|
| 220 | +// GetEstimateFee returns total cost of TX execution in the underlying chain's currency. |
| 221 | +// The value (val) is included in the fee calculation. |
| 222 | +func (w *chainWriter) GetEstimateFee(ctx context.Context, contract, method string, args any, toAddress string, meta *commontypes.TxMeta, val *big.Int) (commontypes.EstimateFee, error) { |
| 223 | + calldata, err := w.encoder.Encode(ctx, args, codec.WrapItemType(contract, method, true)) |
| 224 | + if err != nil { |
| 225 | + return commontypes.EstimateFee{}, fmt.Errorf("%w: failed to encode args", err) |
| 226 | + } |
| 227 | + |
| 228 | + to := common.HexToAddress(toAddress) |
| 229 | + var v assets.Eth |
| 230 | + if val != nil { |
| 231 | + v = assets.Eth(*val) |
| 232 | + } |
| 233 | + |
| 234 | + contractConfig, ok := w.contracts[contract] |
| 235 | + if !ok { |
| 236 | + return commontypes.EstimateFee{}, fmt.Errorf("contract config not found: %v", contract) |
| 237 | + } |
| 238 | + |
| 239 | + methodConfig, ok := contractConfig.Configs[method] |
| 240 | + if !ok { |
| 241 | + return commontypes.EstimateFee{}, fmt.Errorf("method config not found: %v", method) |
| 242 | + } |
| 243 | + |
| 244 | + gasLimit := methodConfig.GasLimit |
| 245 | + if meta != nil && meta.GasLimit != nil { |
| 246 | + gasLimit = meta.GasLimit.Uint64() |
| 247 | + } |
| 248 | + |
| 249 | + from := common.Address{} |
| 250 | + cost, err := w.getMaxCost(ctx, v, calldata, gasLimit, w.maxGasPrice, &from, &to) |
| 251 | + if err != nil { |
| 252 | + return commontypes.EstimateFee{}, err |
| 253 | + } |
| 254 | + |
| 255 | + return commontypes.EstimateFee{ |
| 256 | + Fee: cost, |
| 257 | + Decimals: 18, |
| 258 | + }, nil |
| 259 | +} |
| 260 | + |
| 261 | +func (w *chainWriter) getMaxCost(ctx context.Context, amount assets.Eth, calldata []byte, |
| 262 | + gasLimit uint64, maxGasPrice *assets.Wei, fromAddress, toAddress *common.Address) (*big.Int, error) { |
| 263 | + fee, err := w.GetFeeComponents(ctx) |
| 264 | + var gasPrice *big.Int |
| 265 | + if err != nil { |
| 266 | + w.logger.Warnf("%w: GetFeeComponents failed; use maxFeePrice instead", err) |
| 267 | + gasPrice = fee.ExecutionFee |
| 268 | + } else { |
| 269 | + gasPrice = (*big.Int)(maxGasPrice) |
| 270 | + } |
| 271 | + |
| 272 | + estimateGas, err := w.client.EstimateGas(ctx, ethereum.CallMsg{To: toAddress, Data: calldata}) |
| 273 | + if err != nil { |
| 274 | + w.logger.Warnf("%w: EstimateGas failed; use gasLimit instead", err) |
| 275 | + estimateGas = gasLimit |
| 276 | + } |
| 277 | + |
| 278 | + totalFee := new(big.Int).Mul(gasPrice, big.NewInt(int64(estimateGas))) |
| 279 | + amountWithFees := new(big.Int).Add(amount.ToInt(), totalFee) |
| 280 | + |
| 281 | + return amountWithFees, nil |
| 282 | +} |
| 283 | + |
219 | 284 | func (w *chainWriter) Close() error { |
220 | 285 | return w.StopOnce(w.Name(), func() error { |
221 | 286 | return nil |
|
0 commit comments