diff --git a/shared/services/gas/etherscan/etherscan.go b/shared/services/gas/etherscan/etherscan.go index 41e00b93..9adff49e 100644 --- a/shared/services/gas/etherscan/etherscan.go +++ b/shared/services/gas/etherscan/etherscan.go @@ -28,16 +28,16 @@ import ( "strconv" ) -const gasOracleUrl string = "https://api.etherscan.io/api?module=gastracker&action=gasoracle" +const gasOracleUrl string = "https://api.etherscan.io/v2/api?module=gastracker&action=gasoracle&chainId=1" // Standard response type gasOracleResponse struct { Status uinteger `json:"status"` Message string `json:"message"` Result struct { - SafeGasPrice uinteger `json:"SafeGasPrice"` - ProposeGasPrice uinteger `json:"ProposeGasPrice"` - FastGasPrice uinteger `json:"FastGasPrice"` + SafeGasPrice gasfloat `json:"SafeGasPrice"` + ProposeGasPrice gasfloat `json:"ProposeGasPrice"` + FastGasPrice gasfloat `json:"FastGasPrice"` } `json:"result"` } @@ -115,3 +115,29 @@ func (i *uinteger) UnmarshalJSON(data []byte) error { *i = uinteger(value) return nil } + +// Float type for gas prices (v2 API returns fractional gwei values like "0.13866663") +type gasfloat float64 + +func (f gasfloat) MarshalJSON() ([]byte, error) { + return json.Marshal(strconv.FormatFloat(float64(f), 'f', -1, 64)) +} + +func (f *gasfloat) UnmarshalJSON(data []byte) error { + + // Unmarshal string + var dataStr string + if err := json.Unmarshal(data, &dataStr); err != nil { + return err + } + + // Parse float value + value, err := strconv.ParseFloat(dataStr, 64) + if err != nil { + return err + } + + // Set value and return + *f = gasfloat(value) + return nil +} diff --git a/shared/services/gas/gas.go b/shared/services/gas/gas.go index 8e93f9b8..ab1468dd 100644 --- a/shared/services/gas/gas.go +++ b/shared/services/gas/gas.go @@ -26,7 +26,6 @@ import ( "github.com/stader-labs/stader-node/shared/utils/log" - "github.com/stader-labs/stader-node/shared/services/gas/etherchain" "github.com/stader-labs/stader-node/shared/services/gas/etherscan" "github.com/stader-labs/stader-node/shared/services/stader" cliutils "github.com/stader-labs/stader-node/shared/utils/cli" @@ -90,22 +89,16 @@ func AssignMaxFeeAndLimit(gasInfo staderCore.GasInfo, staderClient *stader.Clien } maxFeeGwei = eth.WeiToGwei(maxFeeWei) } else { - // Try to get the latest gas prices from Etherchain - etherchainData, err := etherchain.GetGasPrices() + // Try to get the latest gas prices from Etherscan + etherscanData, err := etherscan.GetGasPrices() if err == nil { - // Print the Etherchain data and ask for an amount - maxFeeGwei = handleEtherchainGasPrices(etherchainData, maxPriorityFeeGwei) - + // Print the Etherscan data and ask for an amount + maxFeeGwei = handleEtherscanGasPrices(etherscanData, maxPriorityFeeGwei) } else { - // Fallback to Etherscan - fmt.Printf("%sWarning: couldn't get gas estimates from Etherchain - %s\nFalling back to Etherscan%s\n", log.ColorYellow, err.Error(), log.ColorReset) - etherscanData, err := etherscan.GetGasPrices() - if err == nil { - // Print the Etherscan data and ask for an amount - maxFeeGwei = handleEtherscanGasPrices(etherscanData, maxPriorityFeeGwei) - } else { - return fmt.Errorf("Error getting gas price suggestions: %w", err) - } + // Fallback to manual entry + fmt.Printf("%sWarning: couldn't get gas estimates from Etherscan - %s\n", log.ColorYellow, err.Error()) + fmt.Printf("This may be due to Etherscan's free API rate limit (1 request per 5 seconds). Please try again in a few seconds or enter a max fee manually.%s\n", log.ColorReset) + maxFeeGwei = handleManualGasEntry(maxPriorityFeeGwei) } } fmt.Printf("%sUsing a max fee of %.2f gwei and a priority fee of %.2f gwei.\n%s", log.ColorBlue, maxFeeGwei, maxPriorityFeeGwei, log.ColorReset) @@ -126,12 +119,6 @@ func AssignMaxFeeAndLimit(gasInfo staderCore.GasInfo, staderClient *stader.Clien // Get the suggested max fee for service operations func GetHeadlessMaxFeeWei() (*big.Int, error) { - etherchainData, err := etherchain.GetGasPrices() - if err == nil { - return etherchainData.RapidWei, nil - } - - fmt.Printf("%sWarning: couldn't get gas estimates from Etherchain - %s\nFalling back to Etherscan%s\n", log.ColorYellow, err.Error(), log.ColorReset) etherscanData, err := etherscan.GetGasPrices() if err == nil { return eth.GweiToWei(etherscanData.FastGwei), nil @@ -140,8 +127,9 @@ func GetHeadlessMaxFeeWei() (*big.Int, error) { return nil, fmt.Errorf("Error getting gas price suggestions: %w", err) } -func handleEtherchainGasPrices(gasSuggestion etherchain.GasFeeSuggestion, priorityFee float64) float64 { - fastGwei := math.RoundUp(eth.WeiToGwei(gasSuggestion.FastWei)+priorityFee, 0) +func handleEtherscanGasPrices(gasSuggestion etherscan.GasFeeSuggestion, priorityFee float64) float64 { + + fastGwei := math.RoundUp(gasSuggestion.FastGwei+priorityFee, 0) for { desiredPrice := cliutils.Prompt( @@ -155,7 +143,7 @@ func handleEtherchainGasPrices(gasSuggestion etherchain.GasFeeSuggestion, priori desiredPriceFloat, err := strconv.ParseFloat(desiredPrice, 64) if err != nil { - fmt.Printf("Not a valid gas price (%s), try again.", err.Error()) + fmt.Printf("Not a valid gas price (%s), try again.\n", err.Error()) continue } if desiredPriceFloat <= 0 { @@ -168,18 +156,17 @@ func handleEtherchainGasPrices(gasSuggestion etherchain.GasFeeSuggestion, priori } -func handleEtherscanGasPrices(gasSuggestion etherscan.GasFeeSuggestion, priorityFee float64) float64 { - - fastGwei := math.RoundUp(gasSuggestion.FastGwei+priorityFee, 0) +func handleManualGasEntry(priorityFee float64) float64 { for { desiredPrice := cliutils.Prompt( - fmt.Sprintf("Please enter your max fee (including the priority fee) or leave blank for the default of %d gwei:", int(fastGwei)), + "Please enter your max fee (including the priority fee) in gwei (e.g. 2):", "^(?:[1-9]\\d*|0)?(?:\\.\\d+)?$", "Not a valid gas price, try again:") if desiredPrice == "" { - return fastGwei + fmt.Println("Max fee is required, please enter a value.") + continue } desiredPriceFloat, err := strconv.ParseFloat(desiredPrice, 64) diff --git a/shared/version.go b/shared/version.go index 78221a79..282a200d 100644 --- a/shared/version.go +++ b/shared/version.go @@ -21,7 +21,7 @@ package shared const BinaryBucket string = "/stader-node-build/permissionless" const DockerAccount string = "staderlabs" -const StaderVersion string = "1.7.2" +const StaderVersion string = "1.7.3" const Logo string = ` _____ _ _ _ _ 𝅺 diff --git a/stader-cli/service/migration.go b/stader-cli/service/migration.go index 1296fc98..55c0fafb 100644 --- a/stader-cli/service/migration.go +++ b/stader-cli/service/migration.go @@ -94,6 +94,11 @@ func migrate(c *cli.Context) (runBeforeUpgrades, rundAfterUpgrades []ConfigUpgra return nil, nil, err } + v173, err := parseVersion("1.7.3") + if err != nil { + return nil, nil, err + } + // Create the collection of upgraders upgraders := []ConfigUpgrader{ { @@ -160,6 +165,11 @@ func migrate(c *cli.Context) (runBeforeUpgrades, rundAfterUpgrades []ConfigUpgra upgradeFunc: func(_ *cli.Context) error { return nil }, needInstall: true, }, + { + version: v173, + upgradeFunc: func(_ *cli.Context) error { return nil }, + needInstall: true, + }, } staderClient, err := stader.NewClientFromCtx(c)