diff --git a/Makefile b/Makefile index b516132cc..fe17d2d70 100644 --- a/Makefile +++ b/Makefile @@ -27,9 +27,9 @@ ${BIN_DIR}/rocketpool-cli-$1-$2: ${bin_deps} ifndef NO_DOCKER docker run --rm -v ./:/src --user $(shell id -u):$(shell id -g) -e CGO_ENABLED=0 \ -e GOARCH=$2 -e GOOS=$1 --workdir /src -v ~/.cache:/.cache rocketpool/smartnode-builder:${VERSION} \ - go build -o $$@ rocketpool-cli/rocketpool-cli.go + go build -o $$@ ./rocketpool-cli/ else - CGO_ENABLED=0 GOOS=$1 GOARCH=$2 go build -o $$@ ./rocketpool-cli/rocketpool-cli.go + CGO_ENABLED=0 GOOS=$1 GOARCH=$2 go build -o $$@ ./rocketpool-cli/ endif endef diff --git a/rocketpool-cli/auction/bid-lot.go b/rocketpool-cli/auction/bid-lot.go index 404574c22..81ae81df3 100644 --- a/rocketpool-cli/auction/bid-lot.go +++ b/rocketpool-cli/auction/bid-lot.go @@ -109,7 +109,7 @@ func bidOnLot(c *cli.Context) error { maxAmount.Quo(&tmp, eth.EthToWei(1)) // Prompt for maximum amount - if prompt.Confirm(fmt.Sprintf("Would you like to bid the maximum amount of ETH (%.6f ETH)?", math.RoundDown(eth.WeiToEth(&maxAmount), 6))) { + if prompt.Confirm("Would you like to bid the maximum amount of ETH (%.6f ETH)?", math.RoundDown(eth.WeiToEth(&maxAmount), 6)) { amountWei = &maxAmount } else { @@ -145,7 +145,7 @@ func bidOnLot(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to bid %.6f ETH on lot %d? Bids are final and non-refundable.", math.RoundDown(eth.WeiToEth(amountWei), 6), selectedLot.Details.Index))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to bid %.6f ETH on lot %d? Bids are final and non-refundable.", math.RoundDown(eth.WeiToEth(amountWei), 6), selectedLot.Details.Index)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/auction/claim-lot.go b/rocketpool-cli/auction/claim-lot.go index e564fcecd..36120cb56 100644 --- a/rocketpool-cli/auction/claim-lot.go +++ b/rocketpool-cli/auction/claim-lot.go @@ -115,7 +115,7 @@ func claimFromLot(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to claim %d lots?", len(selectedLots)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to claim %d lots?", len(selectedLots))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/auction/recover-lot.go b/rocketpool-cli/auction/recover-lot.go index 330c15c4b..214143df7 100644 --- a/rocketpool-cli/auction/recover-lot.go +++ b/rocketpool-cli/auction/recover-lot.go @@ -115,7 +115,7 @@ func recoverRplFromLot(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to recover %d lots?", len(selectedLots)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to recover %d lots?", len(selectedLots))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/claims/claim-all.go b/rocketpool-cli/claims/claim-all.go index 63b484fb9..649d4fe56 100644 --- a/rocketpool-cli/claims/claim-all.go +++ b/rocketpool-cli/claims/claim-all.go @@ -882,7 +882,7 @@ func claimAll(c *cli.Context, statusOnly bool) error { if autoConfirm { fmt.Printf(" %sContinuing with remaining %d claim(s)...%s\n", colorYellow, remaining, colorReset) } else { - if !prompt.Confirm(fmt.Sprintf(" The above claim failed. Continue with the remaining %d claim(s)?", remaining)) { + if !prompt.Confirm(" The above claim failed. Continue with the remaining %d claim(s)?", remaining) { skippedCount = remaining fmt.Println(" Aborting remaining claims.") break diff --git a/rocketpool-cli/megapool/deposit.go b/rocketpool-cli/megapool/deposit.go index 630e1ca5c..c5ecd175b 100644 --- a/rocketpool-cli/megapool/deposit.go +++ b/rocketpool-cli/megapool/deposit.go @@ -138,7 +138,7 @@ func nodeMegapoolDeposit(c *cli.Context) error { fmt.Printf("The total bond requirement is %.2f ETH.\n", totalBondRequirementEth) fmt.Println() - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("%sNOTE: You are about to create %d new megapool validator(s), requiring a total of: %.2f ETH).%s\nWould you like to continue?", colorYellow, count, totalBondRequirementEth, colorReset))) { + if !(c.Bool("yes") || prompt.Confirm("%sNOTE: You are about to create %d new megapool validator(s), requiring a total of: %.2f ETH).%s\nWould you like to continue?", colorYellow, count, totalBondRequirementEth, colorReset)) { fmt.Println("Cancelled.") return nil } @@ -272,13 +272,13 @@ func nodeMegapoolDeposit(c *cli.Context) error { // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf( + if !(c.Bool("yes") || prompt.Confirm( "You are about to deposit %.6f ETH to create %d new megapool validator(s).\n"+ "%sARE YOU SURE YOU WANT TO DO THIS? %s\n", math.RoundDown(eth.WeiToEth(totalBondRequirement), 6), count, colorYellow, - colorReset))) { + colorReset)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/megapool/dissolve-validator.go b/rocketpool-cli/megapool/dissolve-validator.go index 5fef7f9f1..0a9558bcc 100644 --- a/rocketpool-cli/megapool/dissolve-validator.go +++ b/rocketpool-cli/megapool/dissolve-validator.go @@ -75,7 +75,7 @@ func dissolveValidator(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to DISSOLVE megapool validator ID: %d?", validatorId))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to DISSOLVE megapool validator ID: %d?", validatorId)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/megapool/exit-queue.go b/rocketpool-cli/megapool/exit-queue.go index 4f87a5472..921361af3 100644 --- a/rocketpool-cli/megapool/exit-queue.go +++ b/rocketpool-cli/megapool/exit-queue.go @@ -169,7 +169,7 @@ func exitQueue(c *cli.Context) error { } // Ask for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to exit %d validator(s) from the megapool queue?", len(canExitResponses)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to exit %d validator(s) from the megapool queue?", len(canExitResponses))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/megapool/exit-validator.go b/rocketpool-cli/megapool/exit-validator.go index 1f3b3dbf9..2c9643746 100644 --- a/rocketpool-cli/megapool/exit-validator.go +++ b/rocketpool-cli/megapool/exit-validator.go @@ -83,7 +83,7 @@ func exitValidator(c *cli.Context) error { fmt.Printf("Once your funds have been withdrawn, you can run `rocketpool megapool notify-validator-exit` to distribute them to your withdrawal address.\n\n%s", colorReset) // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to EXIT validator id %d?", validatorId))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to EXIT validator id %d?", validatorId)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/megapool/notify-final-balance.go b/rocketpool-cli/megapool/notify-final-balance.go index d3a3589dd..e9356b8fc 100644 --- a/rocketpool-cli/megapool/notify-final-balance.go +++ b/rocketpool-cli/megapool/notify-final-balance.go @@ -108,7 +108,7 @@ func notifyFinalBalance(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to notify the final balance for validator id %d exit?", validatorId))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to notify the final balance for validator id %d exit?", validatorId)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/megapool/notify-validator-exit.go b/rocketpool-cli/megapool/notify-validator-exit.go index c5d122c91..f4bb11ee5 100644 --- a/rocketpool-cli/megapool/notify-validator-exit.go +++ b/rocketpool-cli/megapool/notify-validator-exit.go @@ -75,7 +75,7 @@ func notifyValidatorExit(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to notify about the validator id %d exit?", validatorId))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to notify about the validator id %d exit?", validatorId)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/megapool/reduce-bond.go b/rocketpool-cli/megapool/reduce-bond.go index e54b1fddb..08fe7f399 100644 --- a/rocketpool-cli/megapool/reduce-bond.go +++ b/rocketpool-cli/megapool/reduce-bond.go @@ -37,7 +37,7 @@ func reduceBond(c *cli.Context) error { if megapoolDetails.Megapool.NodeBond.Cmp(megapoolDetails.Megapool.BondRequirement) > 0 { maxAmountInEth := eth.WeiToEth(megapoolDetails.Megapool.NodeBond.Sub(megapoolDetails.Megapool.NodeBond, megapoolDetails.Megapool.BondRequirement)) fmt.Printf("You have %.6f of excess bond.\n", maxAmountInEth) - if prompt.Confirm(fmt.Sprintf("Do you want to reduce %.6f ETH of your node bond?", maxAmountInEth)) { + if prompt.Confirm("Do you want to reduce %.6f ETH of your node bond?", maxAmountInEth) { // Convert maxAmountInEth to string amount = maxAmountInEth } else { @@ -74,7 +74,7 @@ func reduceBond(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to reduce %.6f of the megapool bond?", math.RoundDown(eth.WeiToEth(amountWei), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to reduce %.6f of the megapool bond?", math.RoundDown(eth.WeiToEth(amountWei), 6))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/megapool/repay-debt.go b/rocketpool-cli/megapool/repay-debt.go index 08fed9518..7cbb195a6 100644 --- a/rocketpool-cli/megapool/repay-debt.go +++ b/rocketpool-cli/megapool/repay-debt.go @@ -66,7 +66,7 @@ func repayDebt(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to repay %.6f ETH of megapool debt?", math.RoundDown(eth.WeiToEth(amountWei), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to repay %.6f ETH of megapool debt?", math.RoundDown(eth.WeiToEth(amountWei), 6))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/megapool/stake.go b/rocketpool-cli/megapool/stake.go index 860931960..da7cd1111 100644 --- a/rocketpool-cli/megapool/stake.go +++ b/rocketpool-cli/megapool/stake.go @@ -68,7 +68,7 @@ func stake(c *cli.Context) error { } // Warning reg the time necessary to build the proof - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("The stake operation will construct a beacon state proof that the deposit for validator ID %d was correct. This will take several seconds to finish.\nDo you want to continue?", validatorId))) { + if !(c.Bool("yes") || prompt.Confirm("The stake operation will construct a beacon state proof that the deposit for validator ID %d was correct. This will take several seconds to finish.\nDo you want to continue?", validatorId)) { fmt.Println("Cancelled.") return nil } @@ -96,7 +96,7 @@ func stake(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to stake validator id %d", validatorId))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to stake validator id %d", validatorId)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/minipool/close.go b/rocketpool-cli/minipool/close.go index 00d2b09da..549a4c5e8 100644 --- a/rocketpool-cli/minipool/close.go +++ b/rocketpool-cli/minipool/close.go @@ -41,11 +41,11 @@ func closeMinipools(c *cli.Context) error { // Post a warning about express ticket provisioning if !details.ExpressTicketsProvisioned { - if !prompt.Confirm(fmt.Sprintf("%sWARNING: The node has unprovisioned express queue ticket(s). Closing minipool(s) without provisioning will reduce the number of express queue tickets the node is eligible for. Please enter `yes` if you've understood this message.%s`", colorRed, colorReset)) { + if !prompt.Confirm("%sWARNING: The node has unprovisioned express queue ticket(s). Closing minipool(s) without provisioning will reduce the number of express queue tickets the node is eligible for. Please enter `yes` if you've understood this message.%s`", colorRed, colorReset) { fmt.Println("Cancelled.") return nil } - if c.Bool("yes") || prompt.Confirm(fmt.Sprintf("%sWould you like to provision express queue tickets for the node?%s", colorYellow, colorReset)) { + if c.Bool("yes") || prompt.Confirm("%sWould you like to provision express queue tickets for the node?%s", colorYellow, colorReset) { // Check if the node can provision express tickets canProvision, err := rp.CanProvisionExpressTickets() if err != nil { @@ -212,7 +212,7 @@ func closeMinipools(c *cli.Context) error { fmt.Printf("\n%sIf you are *sure* you want to close the minipool anyway, rerun this command with the `--confirm-slashing` flag. Doing so WILL RESULT in both your ETH bond and your RPL collateral being slashed.%s\n", colorRed, colorReset) return nil } - if !prompt.ConfirmWithIAgree(fmt.Sprintf("\n%sYou have the `--confirm-slashing` flag enabled. Closing this minipool WILL RESULT in the complete loss of your initial ETH bond and enough of your RPL stake to cover the losses to the staking pool. Please confirm you understand this and want to continue closing the minipool.%s", colorRed, colorReset)) { + if !prompt.ConfirmWithIAgree("\n%sYou have the `--confirm-slashing` flag enabled. Closing this minipool WILL RESULT in the complete loss of your initial ETH bond and enough of your RPL stake to cover the losses to the staking pool. Please confirm you understand this and want to continue closing the minipool.%s", colorRed, colorReset) { fmt.Println("Cancelled.") return nil } @@ -222,7 +222,7 @@ func closeMinipools(c *cli.Context) error { if distributableBalance.Cmp(yellowThreshold) < 0 { // More than the user deposit balance but less than 31.5, ETH will be slashed with a red warning - if !prompt.ConfirmWithIAgree(fmt.Sprintf("%sWARNING: Minipool %s has a distributable balance of %.6f ETH. Closing it in this state WILL RESULT in a loss of ETH. You will only receive %.6f ETH back. Please confirm you understand this and want to continue closing the minipool.%s", colorRed, minipool.Address.Hex(), math.RoundDown(eth.WeiToEth(distributableBalance), 6), math.RoundDown(eth.WeiToEth(minipool.NodeShare), 6), colorReset)) { + if !prompt.ConfirmWithIAgree("%sWARNING: Minipool %s has a distributable balance of %.6f ETH. Closing it in this state WILL RESULT in a loss of ETH. You will only receive %.6f ETH back. Please confirm you understand this and want to continue closing the minipool.%s", colorRed, minipool.Address.Hex(), math.RoundDown(eth.WeiToEth(distributableBalance), 6), math.RoundDown(eth.WeiToEth(minipool.NodeShare), 6), colorReset) { fmt.Println("Cancelled.") return nil } @@ -231,7 +231,7 @@ func closeMinipools(c *cli.Context) error { } if distributableBalance.Cmp(thirtyTwo) < 0 { // More than 31.5 but less than 32, ETH will be slashed with a yellow warning - if !prompt.Confirm(fmt.Sprintf("%sWARNING: Minipool %s has a distributable balance of %.6f ETH. Closing it in this state WILL RESULT in a loss of ETH. You will only receive %.6f ETH back. Please confirm you understand this and want to continue closing the minipool.%s", colorYellow, minipool.Address.Hex(), math.RoundDown(eth.WeiToEth(distributableBalance), 6), math.RoundDown(eth.WeiToEth(minipool.NodeShare), 6), colorReset)) { + if !prompt.Confirm("%sWARNING: Minipool %s has a distributable balance of %.6f ETH. Closing it in this state WILL RESULT in a loss of ETH. You will only receive %.6f ETH back. Please confirm you understand this and want to continue closing the minipool.%s", colorYellow, minipool.Address.Hex(), math.RoundDown(eth.WeiToEth(distributableBalance), 6), math.RoundDown(eth.WeiToEth(minipool.NodeShare), 6), colorReset) { fmt.Println("Cancelled.") return nil } @@ -257,7 +257,7 @@ func closeMinipools(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to close %d minipools?", len(selectedMinipools)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to close %d minipools?", len(selectedMinipools))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/minipool/delegate.go b/rocketpool-cli/minipool/delegate.go index 687646d3b..2993b9397 100644 --- a/rocketpool-cli/minipool/delegate.go +++ b/rocketpool-cli/minipool/delegate.go @@ -109,7 +109,7 @@ func delegateUpgradeMinipools(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to upgrade %d minipools?", len(selectedMinipools)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to upgrade %d minipools?", len(selectedMinipools))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/minipool/dissolve.go b/rocketpool-cli/minipool/dissolve.go index ec2930156..bf0b9b97e 100644 --- a/rocketpool-cli/minipool/dissolve.go +++ b/rocketpool-cli/minipool/dissolve.go @@ -111,7 +111,7 @@ func dissolveMinipools(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to dissolve %d minipool(s)? This action cannot be undone!", len(selectedMinipools)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to dissolve %d minipool(s)? This action cannot be undone!", len(selectedMinipools))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/minipool/distribute.go b/rocketpool-cli/minipool/distribute.go index 54af3f955..fd553288e 100644 --- a/rocketpool-cli/minipool/distribute.go +++ b/rocketpool-cli/minipool/distribute.go @@ -217,7 +217,7 @@ func distributeBalance(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to distribute the ETH balance of %d minipools?", len(selectedMinipools)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to distribute the ETH balance of %d minipools?", len(selectedMinipools))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/minipool/exit.go b/rocketpool-cli/minipool/exit.go index c4456ca88..784a9157d 100644 --- a/rocketpool-cli/minipool/exit.go +++ b/rocketpool-cli/minipool/exit.go @@ -93,7 +93,7 @@ func exitMinipools(c *cli.Context) error { fmt.Printf("Once your funds have been withdrawn, you can run `rocketpool minipool close` to distribute them to your withdrawal address and close the minipool.\n\n%s", colorReset) // Prompt for confirmation - if !(c.Bool("yes") || prompt.ConfirmWithIAgree(fmt.Sprintf("Are you sure you want to exit %d minipool(s)? This action cannot be undone!", len(selectedMinipools)))) { + if !(c.Bool("yes") || prompt.ConfirmWithIAgree("Are you sure you want to exit %d minipool(s)? This action cannot be undone!", len(selectedMinipools))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/minipool/promote.go b/rocketpool-cli/minipool/promote.go index a2c07c7be..47743f9dd 100644 --- a/rocketpool-cli/minipool/promote.go +++ b/rocketpool-cli/minipool/promote.go @@ -108,7 +108,7 @@ func promoteMinipools(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to promote %d minipools?", len(selectedMinipools)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to promote %d minipools?", len(selectedMinipools))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/minipool/reduce-bond.go b/rocketpool-cli/minipool/reduce-bond.go index e6232a518..605bace5b 100644 --- a/rocketpool-cli/minipool/reduce-bond.go +++ b/rocketpool-cli/minipool/reduce-bond.go @@ -128,7 +128,7 @@ func reduceBondAmount(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to reduce the bond for %d minipools from 16 ETH to 8 ETH?", len(selectedMinipools)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to reduce the bond for %d minipools from 16 ETH to 8 ETH?", len(selectedMinipools))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/minipool/refund.go b/rocketpool-cli/minipool/refund.go index eee049fb3..5090cd6ff 100644 --- a/rocketpool-cli/minipool/refund.go +++ b/rocketpool-cli/minipool/refund.go @@ -110,7 +110,7 @@ func refundMinipools(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to refund %d minipools?", len(selectedMinipools)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to refund %d minipools?", len(selectedMinipools))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/minipool/rescue-dissolved.go b/rocketpool-cli/minipool/rescue-dissolved.go index 1e8736362..92ce8d032 100644 --- a/rocketpool-cli/minipool/rescue-dissolved.go +++ b/rocketpool-cli/minipool/rescue-dissolved.go @@ -205,7 +205,7 @@ func rescueDissolved(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to deposit %.6f ETH to rescue minipool %s?", math.RoundDown(depositAmountFloat, 6), selectedMinipool.Address.Hex()))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to deposit %.6f ETH to rescue minipool %s?", math.RoundDown(depositAmountFloat, 6), selectedMinipool.Address.Hex())) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/minipool/stake.go b/rocketpool-cli/minipool/stake.go index fe486c497..fab83ac04 100644 --- a/rocketpool-cli/minipool/stake.go +++ b/rocketpool-cli/minipool/stake.go @@ -114,7 +114,7 @@ func stakeMinipools(c *cli.Context) error { fmt.Println() // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to stake %d minipools?", len(selectedMinipools)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to stake %d minipools?", len(selectedMinipools))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/allow-lock-rpl.go b/rocketpool-cli/node/allow-lock-rpl.go index d57b4e46a..059dc12d5 100644 --- a/rocketpool-cli/node/allow-lock-rpl.go +++ b/rocketpool-cli/node/allow-lock-rpl.go @@ -38,7 +38,7 @@ func setRPLLockingAllowed(c *cli.Context, allowedToLock bool) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(allowString)) { + if !(c.Bool("yes") || prompt.Confirm("%s", allowString)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/claim-unclaimed-rewards.go b/rocketpool-cli/node/claim-unclaimed-rewards.go index cdda875f0..493a60d6a 100644 --- a/rocketpool-cli/node/claim-unclaimed-rewards.go +++ b/rocketpool-cli/node/claim-unclaimed-rewards.go @@ -55,7 +55,7 @@ func claimUnclaimedRewards(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to claim %.6f ETH in unclaimed rewards?", math.RoundDown(eth.WeiToEth(status.UnclaimedRewards), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to claim %.6f ETH in unclaimed rewards?", math.RoundDown(eth.WeiToEth(status.UnclaimedRewards), 6))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/primary-withdrawal-address.go b/rocketpool-cli/node/primary-withdrawal-address.go index 4ec280961..5ea1d21fc 100644 --- a/rocketpool-cli/node/primary-withdrawal-address.go +++ b/rocketpool-cli/node/primary-withdrawal-address.go @@ -83,7 +83,7 @@ func setPrimaryWithdrawalAddress(c *cli.Context, withdrawalAddressOrENS string) return err } - if !prompt.Confirm(fmt.Sprintf("Please confirm you want to send %f ETH to %s.", testAmount, withdrawalAddressString)) { + if !prompt.Confirm("Please confirm you want to send %f ETH to %s.", testAmount, withdrawalAddressString) { fmt.Println("Cancelled.") return nil } @@ -110,7 +110,7 @@ func setPrimaryWithdrawalAddress(c *cli.Context, withdrawalAddressOrENS string) } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to set your node's primary withdrawal address to %s?", withdrawalAddressString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to set your node's primary withdrawal address to %s?", withdrawalAddressString)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/rpl-withdrawal-address.go b/rocketpool-cli/node/rpl-withdrawal-address.go index 7f216c74d..714429789 100644 --- a/rocketpool-cli/node/rpl-withdrawal-address.go +++ b/rocketpool-cli/node/rpl-withdrawal-address.go @@ -95,7 +95,7 @@ func setRPLWithdrawalAddress(c *cli.Context, withdrawalAddressOrENS string) erro return err } - if !prompt.Confirm(fmt.Sprintf("Please confirm you want to send %f ETH to %s.", testAmount, withdrawalAddressString)) { + if !prompt.Confirm("Please confirm you want to send %f ETH to %s.", testAmount, withdrawalAddressString) { fmt.Println("Cancelled.") return nil } @@ -125,7 +125,7 @@ func setRPLWithdrawalAddress(c *cli.Context, withdrawalAddressOrENS string) erro if canResponse.RPLStake.Cmp(common.Big0) == 1 { fmt.Printf("%sNOTE: You currently have %.6f RPL staked. Withdrawing it will *no longer* send it to your primary withdrawal address. It will be sent to the new RPL withdrawal address instead. Please verify you have control over that address before confirming this!%s\n", colorYellow, eth.WeiToEth(canResponse.RPLStake), colorReset) } - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to set your node's RPL withdrawal address to %s?", withdrawalAddressString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to set your node's RPL withdrawal address to %s?", withdrawalAddressString)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/send-message.go b/rocketpool-cli/node/send-message.go index af9e2157e..efe877a86 100644 --- a/rocketpool-cli/node/send-message.go +++ b/rocketpool-cli/node/send-message.go @@ -52,7 +52,7 @@ func sendMessage(c *cli.Context, toAddressOrENS string, message []byte) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to send a message to %s?", toAddressString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to send a message to %s?", toAddressString)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/send.go b/rocketpool-cli/node/send.go index 4a79c28d6..37766e2d8 100644 --- a/rocketpool-cli/node/send.go +++ b/rocketpool-cli/node/send.go @@ -72,13 +72,13 @@ func nodeSend(c *cli.Context, amountRaw float64, sendAll bool, token string, toA fmt.Printf("Node balance: %.8f %s\n\n", canSend.Balance, canSend.TokenSymbol) fmt.Printf("%sWARNING: Please confirm that the above token is the one you intend to send before confirming below!%s\n\n", colorYellow, colorReset) - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to send %.8f of %s to %s? This action cannot be undone!", amountRaw, tokenString, toAddressString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to send %.8f of %s to %s? This action cannot be undone!", amountRaw, tokenString, toAddressString)) { fmt.Println("Cancelled.") return nil } } else { fmt.Printf("Node balance: %.8f %s\n\n", canSend.Balance, token) - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to send %.8f %s to %s? This action cannot be undone!", amountRaw, token, toAddressString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to send %.8f %s to %s? This action cannot be undone!", amountRaw, token, toAddressString)) { fmt.Println("Cancelled.") return nil } @@ -160,7 +160,7 @@ func nodeSendAll(c *cli.Context, rp *rocketpool.Client, token string, toAddress fmt.Printf("Gas reserve: %.8f ETH\n", gasCost) fmt.Printf("Send amount: %.8f ETH\n\n", amountRaw) - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to send %.8f ETH to %s? This action cannot be undone!", amountRaw, toAddressString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to send %.8f ETH to %s? This action cannot be undone!", amountRaw, toAddressString)) { fmt.Println("Cancelled.") return nil } @@ -190,13 +190,13 @@ func nodeSendAll(c *cli.Context, rp *rocketpool.Client, token string, toAddress fmt.Printf("Node balance: %.8f %s\n\n", canSend.Balance, canSend.TokenSymbol) fmt.Printf("%sWARNING: Please confirm that the above token is the one you intend to send before confirming below!%s\n\n", colorYellow, colorReset) - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to send all %.8f of %s to %s? This action cannot be undone!", amountRaw, tokenString, toAddressString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to send all %.8f of %s to %s? This action cannot be undone!", amountRaw, tokenString, toAddressString)) { fmt.Println("Cancelled.") return nil } } else { fmt.Printf("Node balance: %.8f %s\n\n", canSend.Balance, token) - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to send all %.8f %s to %s? This action cannot be undone!", amountRaw, token, toAddressString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to send all %.8f %s to %s? This action cannot be undone!", amountRaw, token, toAddressString)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/stake-rpl-whitelist.go b/rocketpool-cli/node/stake-rpl-whitelist.go index 0f5ed25f9..5510d7ead 100644 --- a/rocketpool-cli/node/stake-rpl-whitelist.go +++ b/rocketpool-cli/node/stake-rpl-whitelist.go @@ -52,7 +52,7 @@ func addAddressToStakeRplWhitelist(c *cli.Context, addressOrENS string) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to allow %s to stake RPL for your node?", addressString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to allow %s to stake RPL for your node?", addressString)) { fmt.Println("Cancelled.") return nil } @@ -113,7 +113,7 @@ func removeAddressFromStakeRplWhitelist(c *cli.Context, addressOrENS string) err } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to remove %s from your RPL staking whitelist?", addressString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to remove %s from your RPL staking whitelist?", addressString)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/stake-rpl.go b/rocketpool-cli/node/stake-rpl.go index 96f6788e7..c205e3198 100644 --- a/rocketpool-cli/node/stake-rpl.go +++ b/rocketpool-cli/node/stake-rpl.go @@ -56,7 +56,7 @@ func nodeStakeRpl(c *cli.Context) error { if status.AccountBalances.FixedSupplyRPL.Cmp(big.NewInt(0)) > 0 { // Confirm swapping RPL - if c.Bool("swap") || prompt.Confirm(fmt.Sprintf("The node has a balance of %.6f old RPL. Would you like to swap it for new RPL before staking?", math.RoundDown(eth.WeiToEth(status.AccountBalances.FixedSupplyRPL), 6))) { + if c.Bool("swap") || prompt.Confirm("The node has a balance of %.6f old RPL. Would you like to swap it for new RPL before staking?", math.RoundDown(eth.WeiToEth(status.AccountBalances.FixedSupplyRPL), 6)) { // Check allowance allowance, err := rp.GetNodeSwapRplAllowance() @@ -134,7 +134,7 @@ func nodeStakeRpl(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to swap %.6f old RPL for new RPL?", math.RoundDown(eth.WeiToEth(status.AccountBalances.FixedSupplyRPL), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to swap %.6f old RPL for new RPL?", math.RoundDown(eth.WeiToEth(status.AccountBalances.FixedSupplyRPL), 6))) { fmt.Println("Cancelled.") return nil } @@ -318,9 +318,9 @@ func nodeStakeRpl(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to stake %.6f RPL? You may request to unstake your staked RPL at any time. The unstaked RPL will be withdrawable after an unstaking period of %s.", + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to stake %.6f RPL? You may request to unstake your staked RPL at any time. The unstaked RPL will be withdrawable after an unstaking period of %s.", math.RoundDown(eth.WeiToEth(amountWei), 6), - status.UnstakingPeriodDuration))) { + status.UnstakingPeriodDuration)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/swap-rpl.go b/rocketpool-cli/node/swap-rpl.go index 0f395313c..45e2ce795 100644 --- a/rocketpool-cli/node/swap-rpl.go +++ b/rocketpool-cli/node/swap-rpl.go @@ -54,7 +54,7 @@ func nodeSwapRpl(c *cli.Context) error { entireAmount := status.AccountBalances.FixedSupplyRPL // Prompt for entire amount - if prompt.Confirm(fmt.Sprintf("Would you like to swap your entire old RPL balance (%.6f RPL)?", math.RoundDown(eth.WeiToEth(entireAmount), 6))) { + if prompt.Confirm("Would you like to swap your entire old RPL balance (%.6f RPL)?", math.RoundDown(eth.WeiToEth(entireAmount), 6)) { amountWei = entireAmount } else { @@ -146,7 +146,7 @@ func nodeSwapRpl(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to swap %.6f old RPL for new RPL?", math.RoundDown(eth.WeiToEth(amountWei), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to swap %.6f old RPL for new RPL?", math.RoundDown(eth.WeiToEth(amountWei), 6))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/utils.go b/rocketpool-cli/node/utils.go index 26e760425..989e4edf7 100644 --- a/rocketpool-cli/node/utils.go +++ b/rocketpool-cli/node/utils.go @@ -110,7 +110,7 @@ func promptTimezone() string { // Confirm detected time zone if timezone != "" { - if !prompt.Confirm(fmt.Sprintf("The detected timezone is '%s', would you like to register using this timezone?", timezone)) { + if !prompt.Confirm("The detected timezone is '%s', would you like to register using this timezone?", timezone) { timezone = "" } else { return timezone @@ -164,7 +164,7 @@ func promptTimezone() string { if len(countryNames) == 0 { for timezone == "" { timezone = prompt.Prompt("Please enter a timezone to register with in the format 'Country/City' (use Etc/UTC if you prefer not to answer):", "^([a-zA-Z_]{2,}\\/)+[a-zA-Z_]{2,}$", "Please enter a timezone in the format 'Country/City' (use Etc/UTC if you prefer not to answer)") - if !prompt.Confirm(fmt.Sprintf("You have chosen to register with the timezone '%s', is this correct?", timezone)) { + if !prompt.Confirm("You have chosen to register with the timezone '%s', is this correct?", timezone) { timezone = "" } } diff --git a/rocketpool-cli/node/withdraw-credit.go b/rocketpool-cli/node/withdraw-credit.go index c6ff59737..2b035e647 100644 --- a/rocketpool-cli/node/withdraw-credit.go +++ b/rocketpool-cli/node/withdraw-credit.go @@ -56,7 +56,7 @@ func nodeWithdrawCredit(c *cli.Context) error { // Get maximum withdrawable amount maxAmount := status.CreditBalance // Prompt for maximum amount - if prompt.Confirm(fmt.Sprintf("You have %.6f ETH of credit that you can withdraw, receiving the equivalent amount in rETH on the node withdrawal address (%s).\n\n Would you like to withdraw the maximum amount of credit?", math.RoundDown(eth.WeiToEth(maxAmount), 6), status.PrimaryWithdrawalAddress)) { + if prompt.Confirm("You have %.6f ETH of credit that you can withdraw, receiving the equivalent amount in rETH on the node withdrawal address (%s).\n\n Would you like to withdraw the maximum amount of credit?", math.RoundDown(eth.WeiToEth(maxAmount), 6), status.PrimaryWithdrawalAddress) { amountWei = maxAmount } else { @@ -91,7 +91,7 @@ func nodeWithdrawCredit(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to withdraw %.6f of credit?", math.RoundDown(eth.WeiToEth(amountWei), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to withdraw %.6f of credit?", math.RoundDown(eth.WeiToEth(amountWei), 6))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/withdraw-eth.go b/rocketpool-cli/node/withdraw-eth.go index 0a927d226..d879b0744 100644 --- a/rocketpool-cli/node/withdraw-eth.go +++ b/rocketpool-cli/node/withdraw-eth.go @@ -57,7 +57,7 @@ func nodeWithdrawEth(c *cli.Context) error { // Get maximum withdrawable amount maxAmount := status.EthOnBehalfBalance // Prompt for maximum amount - if prompt.Confirm(fmt.Sprintf("Would you like to withdraw the maximum amount of staked ETH (%.6f ETH)?", math.RoundDown(eth.WeiToEth(maxAmount), 6))) { + if prompt.Confirm("Would you like to withdraw the maximum amount of staked ETH (%.6f ETH)?", math.RoundDown(eth.WeiToEth(maxAmount), 6)) { amountWei = maxAmount } else { @@ -95,7 +95,7 @@ func nodeWithdrawEth(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to withdraw %.6f ETH?", math.RoundDown(eth.WeiToEth(amountWei), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to withdraw %.6f ETH?", math.RoundDown(eth.WeiToEth(amountWei), 6))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/node/withdraw-rpl.go b/rocketpool-cli/node/withdraw-rpl.go index f088554c8..4546742de 100644 --- a/rocketpool-cli/node/withdraw-rpl.go +++ b/rocketpool-cli/node/withdraw-rpl.go @@ -108,7 +108,7 @@ func nodeWithdrawRpl(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to withdraw %.6f staked RPL? This may decrease your node's RPL rewards.", math.RoundDown(eth.WeiToEth(status.UnstakingRPL), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to withdraw %.6f staked RPL? This may decrease your node's RPL rewards.", math.RoundDown(eth.WeiToEth(status.UnstakingRPL), 6))) { fmt.Println("Cancelled.") return nil } @@ -211,7 +211,7 @@ func nodeWithdrawRpl(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to unstake %.6f RPL?", math.RoundDown(eth.WeiToEth(amountWei), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to unstake %.6f RPL?", math.RoundDown(eth.WeiToEth(amountWei), 6))) { fmt.Println("Cancelled.") return nil } @@ -261,7 +261,7 @@ func nodeWithdrawRpl(c *cli.Context) error { fmt.Printf("You have %.6f legacy RPL and can request to unstake up to %.6f RPL.\n", math.RoundDown(eth.WeiToEth(status.RplStakeLegacy), 6), math.RoundDown(eth.WeiToEth(&maxAmount), 6)) // Prompt for maximum amount - if prompt.Confirm(fmt.Sprintf("Would you like to unstake the maximum amount of legacy RPL (%.6f RPL)?", math.RoundDown(eth.WeiToEth(&maxAmount), 6))) { + if prompt.Confirm("Would you like to unstake the maximum amount of legacy RPL (%.6f RPL)?", math.RoundDown(eth.WeiToEth(&maxAmount), 6)) { amountWei = &maxAmount } else { // Prompt for custom amount @@ -307,7 +307,7 @@ func nodeWithdrawRpl(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to unstake %.6f legacy RPL? This may decrease your node's RPL rewards.", math.RoundDown(eth.WeiToEth(amountWei), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to unstake %.6f legacy RPL? This may decrease your node's RPL rewards.", math.RoundDown(eth.WeiToEth(amountWei), 6))) { fmt.Println("Cancelled.") return nil } @@ -366,7 +366,7 @@ func nodeWithdrawRpl(c *cli.Context) error { maxAmount.Sub(&maxAmount, status.NodeRPLLocked) if maxAmount.Sign() == 1 { // Prompt for maximum amount - if prompt.Confirm(fmt.Sprintf("Would you like to withdraw the maximum amount of staked RPL (%.6f RPL)?", math.RoundDown(eth.WeiToEth(&maxAmount), 6))) { + if prompt.Confirm("Would you like to withdraw the maximum amount of staked RPL (%.6f RPL)?", math.RoundDown(eth.WeiToEth(&maxAmount), 6)) { amountWei = &maxAmount } else { @@ -418,7 +418,7 @@ func nodeWithdrawRpl(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to withdraw %.6f staked RPL? This may decrease your node's RPL rewards.", math.RoundDown(eth.WeiToEth(amountWei), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to withdraw %.6f staked RPL? This may decrease your node's RPL rewards.", math.RoundDown(eth.WeiToEth(amountWei), 6))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/odao/cancel-proposal.go b/rocketpool-cli/odao/cancel-proposal.go index 94e165ad9..785cf3b37 100644 --- a/rocketpool-cli/odao/cancel-proposal.go +++ b/rocketpool-cli/odao/cancel-proposal.go @@ -97,7 +97,7 @@ func cancelProposal(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to cancel proposal %d?", selectedProposal.ID))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to cancel proposal %d?", selectedProposal.ID)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/odao/execute-proposal.go b/rocketpool-cli/odao/execute-proposal.go index 3cfaff2c6..53fb68a3d 100644 --- a/rocketpool-cli/odao/execute-proposal.go +++ b/rocketpool-cli/odao/execute-proposal.go @@ -116,7 +116,7 @@ func executeProposal(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to execute %d proposals?", len(selectedProposals)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to execute %d proposals?", len(selectedProposals))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/odao/execute-upgrade.go b/rocketpool-cli/odao/execute-upgrade.go index 40689b686..f8b4d7630 100644 --- a/rocketpool-cli/odao/execute-upgrade.go +++ b/rocketpool-cli/odao/execute-upgrade.go @@ -171,7 +171,7 @@ func executeUpgrade(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to execute %d proposals?", len(selectedProposals)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to execute %d proposals?", len(selectedProposals))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/odao/join.go b/rocketpool-cli/odao/join.go index cd13547b5..b239d799d 100644 --- a/rocketpool-cli/odao/join.go +++ b/rocketpool-cli/odao/join.go @@ -38,7 +38,7 @@ func join(c *cli.Context) error { if status.AccountBalances.FixedSupplyRPL.Cmp(big.NewInt(0)) > 0 { // Confirm swapping RPL - if c.Bool("swap") || prompt.Confirm(fmt.Sprintf("The node has a balance of %.6f old RPL. Would you like to swap it for new RPL before transferring your bond?", math.RoundDown(eth.WeiToEth(status.AccountBalances.FixedSupplyRPL), 6))) { + if c.Bool("swap") || prompt.Confirm("The node has a balance of %.6f old RPL. Would you like to swap it for new RPL before transferring your bond?", math.RoundDown(eth.WeiToEth(status.AccountBalances.FixedSupplyRPL), 6)) { // Check allowance allowance, err := rp.GetNodeSwapRplAllowance() @@ -72,7 +72,7 @@ func join(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Do you want to let the new RPL contract interact with your legacy RPL?"))) { + if !(c.Bool("yes") || prompt.Confirm("Do you want to let the new RPL contract interact with your legacy RPL?")) { fmt.Println("Cancelled.") return nil } @@ -116,7 +116,7 @@ func join(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to swap %.6f old RPL for new RPL?", math.RoundDown(eth.WeiToEth(status.AccountBalances.FixedSupplyRPL), 6)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to swap %.6f old RPL for new RPL?", math.RoundDown(eth.WeiToEth(status.AccountBalances.FixedSupplyRPL), 6))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/odao/leave.go b/rocketpool-cli/odao/leave.go index 496483ac5..5a986424d 100644 --- a/rocketpool-cli/odao/leave.go +++ b/rocketpool-cli/odao/leave.go @@ -46,7 +46,7 @@ func leave(c *cli.Context) error { } // Prompt for node address - if prompt.Confirm(fmt.Sprintf("Would you like to refund your RPL bond to your node account (%s)?", wallet.AccountAddress.Hex())) { + if prompt.Confirm("Would you like to refund your RPL bond to your node account (%s)?", wallet.AccountAddress.Hex()) { bondRefundAddress = wallet.AccountAddress } else { @@ -81,7 +81,7 @@ func leave(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to leave the oracle DAO and refund your RPL bond to %s? This action cannot be undone!", bondRefundAddress.Hex()))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to leave the oracle DAO and refund your RPL bond to %s? This action cannot be undone!", bondRefundAddress.Hex())) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/odao/penalise-megapool.go b/rocketpool-cli/odao/penalise-megapool.go index 4948a5325..75b18f8c1 100644 --- a/rocketpool-cli/odao/penalise-megapool.go +++ b/rocketpool-cli/odao/penalise-megapool.go @@ -49,7 +49,7 @@ func penaliseMegapool(c *cli.Context, megapoolAddress common.Address, block *big } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to penalise %.6f megapool %s at block %s?", math.RoundDown(eth.WeiToEth(amountWei), 6), megapoolAddress, block))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to penalise %.6f megapool %s at block %s?", math.RoundDown(eth.WeiToEth(amountWei), 6), megapoolAddress, block)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/odao/vote-proposal.go b/rocketpool-cli/odao/vote-proposal.go index 636b1df43..acfe2543e 100644 --- a/rocketpool-cli/odao/vote-proposal.go +++ b/rocketpool-cli/odao/vote-proposal.go @@ -145,7 +145,7 @@ func voteOnProposal(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to vote %s proposal %d? Your vote cannot be changed later.", supportLabel, selectedProposal.ID))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to vote %s proposal %d? Your vote cannot be changed later.", supportLabel, selectedProposal.ID)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/pdao/claim-bonds.go b/rocketpool-cli/pdao/claim-bonds.go index 050922421..bfed61c56 100644 --- a/rocketpool-cli/pdao/claim-bonds.go +++ b/rocketpool-cli/pdao/claim-bonds.go @@ -110,7 +110,7 @@ func claimBonds(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to claim bonds and rewards from %d proposals?", len(selectedClaims)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to claim bonds and rewards from %d proposals?", len(selectedClaims))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/pdao/defeat-proposal.go b/rocketpool-cli/pdao/defeat-proposal.go index 2230c72fb..23682b696 100644 --- a/rocketpool-cli/pdao/defeat-proposal.go +++ b/rocketpool-cli/pdao/defeat-proposal.go @@ -48,7 +48,7 @@ func defeatProposal(c *cli.Context, proposalID uint64, challengedIndex uint64) e } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to defeat proposal %d?", proposalID))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to defeat proposal %d?", proposalID)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/pdao/execute-proposal.go b/rocketpool-cli/pdao/execute-proposal.go index 6fdc08fa8..5d2c5c221 100644 --- a/rocketpool-cli/pdao/execute-proposal.go +++ b/rocketpool-cli/pdao/execute-proposal.go @@ -121,7 +121,7 @@ func executeProposal(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to execute %d proposals?", len(selectedProposals)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to execute %d proposals?", len(selectedProposals))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/pdao/finalize-proposal.go b/rocketpool-cli/pdao/finalize-proposal.go index 3435e5a49..349892f8a 100644 --- a/rocketpool-cli/pdao/finalize-proposal.go +++ b/rocketpool-cli/pdao/finalize-proposal.go @@ -45,7 +45,7 @@ func finalizeProposal(c *cli.Context, proposalID uint64) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to finalize proposal %d?", proposalID))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to finalize proposal %d?", proposalID)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/pdao/invite-sc.go b/rocketpool-cli/pdao/invite-sc.go index 438aefb21..1baa5a897 100644 --- a/rocketpool-cli/pdao/invite-sc.go +++ b/rocketpool-cli/pdao/invite-sc.go @@ -61,7 +61,7 @@ func proposeSecurityCouncilInvite(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to propose inviting %s (%s) to the security council?", id, address.Hex()))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to propose inviting %s (%s) to the security council?", id, address.Hex())) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/pdao/kick-sc.go b/rocketpool-cli/pdao/kick-sc.go index 7d804d4f7..a177f9bbb 100644 --- a/rocketpool-cli/pdao/kick-sc.go +++ b/rocketpool-cli/pdao/kick-sc.go @@ -118,7 +118,7 @@ func proposeSecurityCouncilKick(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to propose kicking %s (%s) from the security council?", *id, address.Hex()))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to propose kicking %s (%s) from the security council?", *id, address.Hex())) { fmt.Println("Cancelled.") return nil } @@ -165,7 +165,7 @@ func proposeSecurityCouncilKick(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to propose kicking these members from the security council?\n%s", kickString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to propose kicking these members from the security council?\n%s", kickString)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/pdao/recurring-spend.go b/rocketpool-cli/pdao/recurring-spend.go index e4d48736b..ced7df750 100644 --- a/rocketpool-cli/pdao/recurring-spend.go +++ b/rocketpool-cli/pdao/recurring-spend.go @@ -70,7 +70,7 @@ func proposeRecurringSpend(c *cli.Context) error { } } startTime := time.Unix(int64(startTimeUnix), 0) - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("The provided timestamp corresponds to %s - is this correct?", startTime.UTC().String()))) { + if !(c.Bool("yes") || prompt.Confirm("The provided timestamp corresponds to %s - is this correct?", startTime.UTC().String())) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/pdao/replace-sc.go b/rocketpool-cli/pdao/replace-sc.go index ff7c7bbf4..72f6c5c8d 100644 --- a/rocketpool-cli/pdao/replace-sc.go +++ b/rocketpool-cli/pdao/replace-sc.go @@ -97,7 +97,7 @@ func proposeSecurityCouncilReplace(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to propose removing %s (%s) from the security council and inviting %s (%s)?", oldID, oldAddress.Hex(), newID, newAddress.Hex()))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to propose removing %s (%s) from the security council and inviting %s (%s)?", oldID, oldAddress.Hex(), newID, newAddress.Hex())) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/pdao/vote-proposal.go b/rocketpool-cli/pdao/vote-proposal.go index a0d1686c2..5e6c8024f 100644 --- a/rocketpool-cli/pdao/vote-proposal.go +++ b/rocketpool-cli/pdao/vote-proposal.go @@ -172,7 +172,7 @@ func voteOnProposal(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to %s with a vote for '%s' on proposal %d? Your vote cannot be changed later.", actionString, voteDirectionLabel, selectedProposal.ID))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to %s with a vote for '%s' on proposal %d? Your vote cannot be changed later.", actionString, voteDirectionLabel, selectedProposal.ID)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/pdao/voting.go b/rocketpool-cli/pdao/voting.go index 6c9cec6bb..49c780e62 100644 --- a/rocketpool-cli/pdao/voting.go +++ b/rocketpool-cli/pdao/voting.go @@ -51,7 +51,7 @@ func pdaoSetVotingDelegate(c *cli.Context, nameOrAddress string) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want %s to represent your node in Rocket Pool on-chain governance proposals?", addressString))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want %s to represent your node in Rocket Pool on-chain governance proposals?", addressString)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/queue/assign-deposits.go b/rocketpool-cli/queue/assign-deposits.go index 51c8aea41..269a04ab7 100644 --- a/rocketpool-cli/queue/assign-deposits.go +++ b/rocketpool-cli/queue/assign-deposits.go @@ -94,7 +94,7 @@ func assignDeposits(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to assign %d validators?", maxValidators))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to assign %d validators?", maxValidators)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/rocketpool-cli.go b/rocketpool-cli/rocketpool-cli.go index c98d88cea..2599fb2fd 100644 --- a/rocketpool-cli/rocketpool-cli.go +++ b/rocketpool-cli/rocketpool-cli.go @@ -18,6 +18,7 @@ import ( "github.com/rocket-pool/smartnode/rocketpool-cli/queue" "github.com/rocket-pool/smartnode/rocketpool-cli/security" "github.com/rocket-pool/smartnode/rocketpool-cli/service" + "github.com/rocket-pool/smartnode/rocketpool-cli/update" "github.com/rocket-pool/smartnode/rocketpool-cli/wallet" "github.com/rocket-pool/smartnode/shared" "github.com/rocket-pool/smartnode/shared/services/rocketpool" @@ -110,6 +111,27 @@ A special thanks to the Rocket Pool community for all their contributions. service.RegisterCommands(app, "service", []string{"s"}) wallet.RegisterCommands(app, "wallet", []string{"w"}) + // Add a command that updates the smart node cli. + app.Commands = append(app.Commands, cli.Command{ + Name: "update", + Usage: "Update the cli binary", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "yes, y", + Usage: "Automatically confirm the update", + }, + cli.BoolFlag{ + Name: "force, f", + Usage: "Force the update even if the current version is the latest", + }, + cli.BoolFlag{ + Name: "skip-signature-verification, s", + Usage: "Don't verify the singature of the release", + }, + }, + Action: update.Update, + }) + app.Before = func(c *cli.Context) error { // Check user ID if os.Getuid() == 0 && !c.GlobalBool("allow-root") { diff --git a/rocketpool-cli/security/cancel-proposal.go b/rocketpool-cli/security/cancel-proposal.go index e386cb232..157309597 100644 --- a/rocketpool-cli/security/cancel-proposal.go +++ b/rocketpool-cli/security/cancel-proposal.go @@ -97,7 +97,7 @@ func cancelProposal(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to cancel proposal %d?", selectedProposal.ID))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to cancel proposal %d?", selectedProposal.ID)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/security/execute-proposal.go b/rocketpool-cli/security/execute-proposal.go index 7f93b13bf..ab5765ef7 100644 --- a/rocketpool-cli/security/execute-proposal.go +++ b/rocketpool-cli/security/execute-proposal.go @@ -116,7 +116,7 @@ func executeProposal(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to execute %d proposals?", len(selectedProposals)))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to execute %d proposals?", len(selectedProposals))) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/security/vote-proposal.go b/rocketpool-cli/security/vote-proposal.go index 4ddd3afc4..56f2e6674 100644 --- a/rocketpool-cli/security/vote-proposal.go +++ b/rocketpool-cli/security/vote-proposal.go @@ -145,7 +145,7 @@ func voteOnProposal(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to vote %s proposal %d? Your vote cannot be changed later.", supportLabel, selectedProposal.ID))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to vote %s proposal %d? Your vote cannot be changed later.", supportLabel, selectedProposal.ID)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/service/service.go b/rocketpool-cli/service/service.go index 9f5a8cd13..42d77abcc 100644 --- a/rocketpool-cli/service/service.go +++ b/rocketpool-cli/service/service.go @@ -58,10 +58,10 @@ func installService(c *cli.Context) error { dataPath := "" // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf( + if !(c.Bool("yes") || prompt.Confirm( "The Rocket Pool %s service will be installed.\n\n%sIf you're upgrading, your existing configuration will be backed up and preserved.\nAll of your previous settings will be migrated automatically.%s\nAre you sure you want to continue?", shared.RocketPoolVersion(), colorGreen, colorReset, - ))) { + )) { fmt.Println("Cancelled.") return nil } @@ -555,7 +555,7 @@ func startService(c *cli.Context, ignoreConfigSuggestion bool) error { fmt.Println() fmt.Println("**If you did NOT change clients, you can safely ignore this warning.**") fmt.Println() - if !prompt.Confirm(fmt.Sprintf("Press y when you understand the above warning, have waited, and are ready to start Rocket Pool:%s", colorReset)) { + if !prompt.Confirm("Press y when you understand the above warning, have waited, and are ready to start Rocket Pool:%s", colorReset) { fmt.Println("Cancelled.") return nil } @@ -1006,7 +1006,7 @@ func pauseService(c *cli.Context) (bool, error) { func terminateService(c *cli.Context) error { // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("%sWARNING: Are you sure you want to terminate the Rocket Pool service? Any staking minipools will be penalized, your ETH1 and ETH2 chain databases will be deleted, you will lose ALL of your sync progress, and you will lose your Prometheus metrics database!\nAfter doing this, you will have to **reinstall** the Smart Node uses `rocketpool service install -d` in order to use it again.%s", colorRed, colorReset))) { + if !(c.Bool("yes") || prompt.Confirm("%sWARNING: Are you sure you want to terminate the Rocket Pool service? Any staking minipools will be penalized, your ETH1 and ETH2 chain databases will be deleted, you will lose ALL of your sync progress, and you will lose your Prometheus metrics database!\nAfter doing this, you will have to **reinstall** the Smart Node uses `rocketpool service install -d` in order to use it again.%s", colorRed, colorReset)) { fmt.Println("Cancelled.") return nil } @@ -1227,7 +1227,7 @@ func resyncEth1(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("%sAre you SURE you want to delete and resync your main ETH1 client from scratch? This cannot be undone!%s", colorRed, colorReset))) { + if !(c.Bool("yes") || prompt.Confirm("%sAre you SURE you want to delete and resync your main ETH1 client from scratch? This cannot be undone!%s", colorRed, colorReset)) { fmt.Println("Cancelled.") return nil } @@ -1342,7 +1342,7 @@ func resyncEth2(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("%sAre you SURE you want to delete and resync your ETH2 client from scratch? This cannot be undone!%s", colorRed, colorReset))) { + if !(c.Bool("yes") || prompt.Confirm("%sAre you SURE you want to delete and resync your ETH2 client from scratch? This cannot be undone!%s", colorRed, colorReset)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/update/assets/fornax-signing-key.asc b/rocketpool-cli/update/assets/fornax-signing-key.asc new file mode 100644 index 000000000..1ccc74763 --- /dev/null +++ b/rocketpool-cli/update/assets/fornax-signing-key.asc @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGNBGecNPsBDADVeVogA3C25W0E5W8UcTjrQWz5a0w6kdcayo1aN80kCDSxNiPV +LmCrCxv6jXV8mN+oL8mR/UsMWSQeWCppVaHSZD0CfJqaLZYkX1RY3cEJp2hYqLFv +BlBXOKugonjR/djteMDS0DSKxVNKrNhC1cZ+pcATQBxF8beiQaZ1k95p8uwlIUFQ +zXAv6pHKYidWZ/GvUFg4iPM8n07AH4IJLS2DuJi/lS7003LJ3ZH8vxTuZ6cY4kxI +87cZv6OZVg1PuisVEmqBnSfIdvpeb2R53lCT/ikwmZ10wfEg6M3FTnY6t/rI1lVt +EmQUBPObZRMSc1v6oSMszTxhw0F3oLmSXc+iEm7DSumHJu08OyCfQCH24dsd1tu8 +L9rTxP2nevVkDy5OLwdL4nz1/2WR2CoDjM9Opih2Y3xa1zV9yk7iJ0gwM55yfB+P +YXzNSz+YDUBh94IYDh5+QqcBN1hNTvSQ7+eA40Q/CwnopxpNFO+/fRmwBv21YvS3 +bZaPuMqbDYuyf5sAEQEAAbQdRm9ybmF4IDxkYW50ZUByb2NrZXRwb29sLm5ldD6J +Ac4EEwEKADgWIQRtPpYL1ALGRkKh7IRlECPWLnC13QUCZ5w0+wIbAwULCQgHAgYV +CgkICwIEFgIDAQIeAQIXgAAKCRBlECPWLnC13S2/DADGh0BLyiNS3t+roSc7Sxdx +oIrBLkS3WkTa7fPmRfa3AXZ/IDm6pS/f20w2Rrpx9xBdoNmUXy1vXQmw10+kdQU7 +m/eP1naw3eCrhyeYBBbeimgh0+26K/RhMefMHLuOAPsNr2F4rnSyDs14cPuYllnM +KmkLA+s/asDM+KiUkHgNvncDi20nS7DsWE2Gh4N+8+SKE/rZFxRZ9TJ2k1UCV5KO +k78wc9lAoTr+bzmnycKi3gO109xevDlK8gj8FGlvoTL+tOq8t52zzPCoeb+8fKrO +tuM3nrYe+KUcSVHGobFPVp1zlX38RU66+EBgHpq85vA9wAIOosJv2ILdQT5iPMy7 +ZP+7jko1+ENiXgOux62rTv7JuNhilsSTamHBJB2JW3K6ncK1wBlRgUxOc2IClfSU +l7MvhHsxjAJOkK6AkNpS6tHwSYekOIB4HmChWtGWeRYZEdls/VqxMmRYa4nZPGQ6 +a+omJc7z8uS42LxniVeDxDN/XQownE48HpXNeo9LhbG5AY0EZ5w0+wEMANOVQZAH +z0uptP+932HCcbtWbbQZk7GTICAWq+fU+902z0DMoAYzkYOE9x/oL8I44N7IHq5s +k4OT+rEL6dsq0LbCRik0oiiFhKiioUWK19kTT0ATVmaF7dF/eB6pg38nm6TcHtVE +BvVbk1sF1ruDDh/EHvRLftvffxJ29QJ5NE0FTh3MAPCXhmC/SWGT8yPbYku6YGhf +uTIKu1pe7jXA1mxf0v1qGcOyO2Ldu8ePh/7GX6gshyLSA6NAxDiEzxh6XXPOfj1J +Od3gBKemxFxv3a6dp+MDJgc0Z1WsC+4du+hcoesTlgVEwJqbbIYrbq1TXT194qpM +bJrZZmboiy77mgySpuOQW/MlJsyOU7qMuy0Xdd0Sf1MNpPNUJdLpj81Hjdkn49Sb +vWyAi6DS9PzzIc706ULXh9fptqk0pF8DVePQUsHLSRYOGZsVRV92b2mblM6i5BoH +4MjyOB59dCEC+VUVtzKFxTKXKkEBbJDQzbfTCvHiQ3jtGf5ZwO32IMOsbwARAQAB +iQG2BBgBCgAgFiEEbT6WC9QCxkZCoeyEZRAj1i5wtd0FAmecNPsCGwwACgkQZRAj +1i5wtd2cvwwApFPDNicdY0tqAFSZ4Utm2qF+Pwq8UgbOExKhcVs3RhSR1GSdjKA8 +fhJcuRMsjsqziuOmt7ihX/nSK70l3j3iDX9XAZCHLmTR3qupKhaKBWqcIEhaKSDY +ED6GmDFCiRr4g8vRqCuRvX2dlYnWFwuzA7Z0VC0oscf8EUoN8dXd5MmY1EOxasYT +vOH5JA1CjQOplqbMo+WnxkKWsNnj8k3H5Tz/X48S9HvHLHNiEeHiYQtuVUO3qhuM +Xa3K0NuMQKhuHXkgrOwg01USy4hMCHMlEfj5vIsf/C9PFkd4Y8oV/XIothIlgs+J +7Q8yji1dCtPxEBURkvFZdRHBsDM4VE2s0xnNT0huh0JONbTG6i1eVX+c/9JSS/50 +5JJlyEnQKn4xf1ekuB9L9CUg3oZ5KLGJnDyEu9LNsY8UN1qrFtRKTr4/cwVZyElA +dWD+ShHZs6w0Mc+rxgCACRNG8yRqaKW5/2VxFUSDhONP87FS1rQLOY7vv4aeMrI/ +rw7blEdnSAIt +=Fnek +-----END PGP PUBLIC KEY BLOCK----- diff --git a/rocketpool-cli/update/assets/keyring.go b/rocketpool-cli/update/assets/keyring.go new file mode 100644 index 000000000..c949c7eae --- /dev/null +++ b/rocketpool-cli/update/assets/keyring.go @@ -0,0 +1,25 @@ +package assets + +import ( + "bytes" + _ "embed" + "io" + + "golang.org/x/crypto/openpgp" +) + +//go:embed fornax-signing-key.asc +var fornaxSigningKey []byte +var entityList openpgp.EntityList + +func init() { + var err error + entityList, err = openpgp.ReadArmoredKeyRing(bytes.NewReader(fornaxSigningKey)) + if err != nil { + panic(err) + } +} + +func VerifySignedBinary(binary io.Reader, signature io.Reader) (signer *openpgp.Entity, err error) { + return openpgp.CheckDetachedSignature(entityList, binary, signature) +} diff --git a/rocketpool-cli/update/update.go b/rocketpool-cli/update/update.go new file mode 100644 index 000000000..976b3d71d --- /dev/null +++ b/rocketpool-cli/update/update.go @@ -0,0 +1,238 @@ +package update + +import ( + "fmt" + "io" + "net/http" + "os" + "os/exec" + "runtime" + "strings" + + "github.com/rocket-pool/smartnode/rocketpool-cli/update/assets" + "github.com/rocket-pool/smartnode/shared" + "github.com/rocket-pool/smartnode/shared/services/rocketpool" + cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" + "github.com/rocket-pool/smartnode/shared/utils/cli/prompt" + "github.com/urfave/cli" +) + +const ( + downloadUrlFormatString = "https://github.com/rocket-pool/smartnode/releases/latest/download/rocketpool-cli-%s-%s" +) + +func validateOsArch() error { + + switch runtime.GOARCH { + case "amd64": + case "arm64": + default: + return fmt.Errorf("unsupported architecture: %s", runtime.GOARCH) + } + + switch runtime.GOOS { + case "linux": + case "darwin": + default: + return fmt.Errorf("unsupported operating system: %s", runtime.GOOS) + } + + return nil +} + +func errorPartialSuccess(err error) { + fmt.Fprintln(os.Stderr, "An error occurred after the cli binary was updated, but before the service was.") + fmt.Fprintln(os.Stderr, "The error was:") + fmt.Fprintf(os.Stderr, " %s\n", cliutils.Red(err.Error())) + fmt.Fprintln(os.Stderr) + printPartialSuccessNextSteps() + os.Exit(1) +} + +func printPartialSuccessNextSteps() { + fmt.Println("Please complete the following steps to complete the update:") + fmt.Println(" Run `rocketpool service stop` to stop the service") + fmt.Println(" Run `rocketpool service install -d` to upgrade the service") + fmt.Println(" Run `rocketpool service start` to start the service") +} + +func forkCommand(binaryPath string, yes bool, args ...string) *exec.Cmd { + cmd := exec.Command(binaryPath, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + if yes { + cmd.Args = append(cmd.Args, "--yes") + } + return cmd +} + +func Update(c *cli.Context) error { + // Get RP client + rp := rocketpool.NewClientFromCtx(c) + defer rp.Close() + + // Get the config + cfg, _, err := rp.LoadConfig() + if err != nil { + return fmt.Errorf("Error loading configuration: %w", err) + } + + if cfg.IsNativeMode { + fmt.Println("You are using Native Mode.") + fmt.Println("The Smart Node cannot update the cli for you (yet), you'll have to do it manually.") + fmt.Println("Please follow the instructions at https://docs.rocketpool.net/node-staking/updates#updating-the-smartnode-stack") + fmt.Println() + return fmt.Errorf("native mode not supported yet") + } + + oldBinaryPath, err := os.Executable() + if err != nil { + return fmt.Errorf("error getting path of current executable: %w", err) + } + + // Validate the OS and architecture + err = validateOsArch() + if err != nil { + return err + } + + fmt.Printf("Your detected os/architecture is %s/%s.\n", cliutils.Green(runtime.GOOS), cliutils.Green(runtime.GOARCH)) + fmt.Println() + + if !c.Bool("yes") { + ok := prompt.Confirm("The cli at %s will be replaced. Continue?", cliutils.Yellow(oldBinaryPath)) + if !ok { + return nil + } + } + fmt.Printf("Replacing the cli at %s with the latest version...\n", oldBinaryPath) + + // Create a temporary directory to download the new binary to + tempDir, err := os.MkdirTemp("", "rocketpool-cli-update-") + if err != nil { + return fmt.Errorf("error creating temporary directory: %w", err) + } + defer os.RemoveAll(tempDir) + + // Create a file that is executable and has the correct permissions + tempFile, err := os.CreateTemp(tempDir, "rocketpool-cli-update-*.bin") + if err != nil { + return fmt.Errorf("error creating temporary file: %w", err) + } + tempFile.Chmod(0755) + + // Download the new binary + downloadUrl := fmt.Sprintf(downloadUrlFormatString, runtime.GOOS, runtime.GOARCH) + fmt.Printf("Downloading the new binary from %s\n", cliutils.Green(downloadUrl)) + fmt.Println() + response, err := http.Get(downloadUrl) + if err != nil { + return fmt.Errorf("error downloading new binary: %w", err) + } + if response.StatusCode != 200 { + return fmt.Errorf("error downloading new binary: %s", response.Status) + } + defer response.Body.Close() + if !c.Bool("skip-signature-verification") { + // Download the signature file + fmt.Println("Verifying the binary signature") + signatureUrl := fmt.Sprintf("%s.sig", downloadUrl) + fmt.Printf("Downloading the signature from %s\n", signatureUrl) + signatureResponse, err := http.Get(signatureUrl) + if err != nil { + return fmt.Errorf("error downloading signature: %w", err) + } + defer signatureResponse.Body.Close() + if signatureResponse.StatusCode != 200 { + return fmt.Errorf("error downloading signature: %s", signatureResponse.Status) + } + teeReader := io.TeeReader(response.Body, tempFile) + signer, err := assets.VerifySignedBinary(teeReader, signatureResponse.Body) + if err != nil { + return fmt.Errorf("error verifying signed binary: %w", err) + } + fmt.Printf("Signed by %s\n", cliutils.Green(signer.PrimaryKey.KeyIdString())) + for _, identity := range signer.Identities { + fmt.Printf(" %s\n", cliutils.Green(identity.Name)) + } + } else { + _, err = io.Copy(tempFile, response.Body) + if err != nil { + return fmt.Errorf("error copying new binary to temporary file: %w", err) + } + } + tempFile.Close() + + // Fork off a process to get the new binary's version and compare + // it with the current version + cmd := exec.Command(tempFile.Name(), "--version") + output, err := cmd.Output() + if err != nil { + return fmt.Errorf("error getting new binary's version: %w", err) + } + newVersion := strings.TrimSpace(string(output)) + newVersion = strings.TrimPrefix(newVersion, "rocketpool version ") + + if strings.EqualFold(shared.RocketPoolVersion(), newVersion) && !c.Bool("force") { + fmt.Println(cliutils.Green(fmt.Sprintf("You are already on the latest version of smartnode: %s.", newVersion))) + return nil + } + + fmt.Printf("Updating from %s to %s\n", cliutils.Yellow(shared.RocketPoolVersion()), cliutils.Green(newVersion)) + + // Rename the temporary file to the actual binary + err = os.Rename(tempFile.Name(), oldBinaryPath) + if err != nil { + return fmt.Errorf("error replacing binary: %w", err) + } + + fmt.Println() + fmt.Println(cliutils.Green("The cli has been updated.")) + fmt.Println() + + if !c.Bool("yes") { + if !prompt.Confirm("Would you like to automatically stop, upgrade, and restart the service to complete the update?") { + printPartialSuccessNextSteps() + return nil + } + } + + fmt.Println("=========================================") + fmt.Println("========= Stopping service... ===========") + fmt.Println("=========================================") + stopCmd := []string{"service", "stop"} + cmd = forkCommand(oldBinaryPath, c.Bool("yes"), stopCmd...) + err = cmd.Run() + if err != nil { + errorPartialSuccess(err) + return nil + } + + fmt.Println("=========================================") + fmt.Println("========= Upgrading service... ==========") + fmt.Println("=========================================") + cmd = forkCommand(oldBinaryPath, c.Bool("yes"), "service", "install", "-d") + err = cmd.Run() + if err != nil { + errorPartialSuccess(err) + return nil + } + + fmt.Println("=========================================") + fmt.Println("========= Starting service... ===========") + fmt.Println("=========================================") + cmd = forkCommand(oldBinaryPath, c.Bool("yes"), "service", "start") + err = cmd.Run() + if err != nil { + errorPartialSuccess(err) + return nil + } + + fmt.Println(cliutils.Green(fmt.Sprintf("The upgrade to Smart Node %s has been completed.", newVersion))) + fmt.Println() + fmt.Println(cliutils.Yellow("Please monitor your validators for a few minutes for issues.")) + fmt.Println() + + return nil +} diff --git a/rocketpool-cli/wallet/masquerade.go b/rocketpool-cli/wallet/masquerade.go index 603a47feb..b6791cb4e 100644 --- a/rocketpool-cli/wallet/masquerade.go +++ b/rocketpool-cli/wallet/masquerade.go @@ -29,7 +29,7 @@ func masquerade(c *cli.Context) error { } // Prompt for confirmation - if !(c.Bool("yes") || prompt.Confirm(fmt.Sprintf("Are you sure you want to masquerade as %s%s%s?", colorBlue, addressString, colorReset))) { + if !(c.Bool("yes") || prompt.Confirm("Are you sure you want to masquerade as %s%s%s?", colorBlue, addressString, colorReset)) { fmt.Println("Cancelled.") return nil } diff --git a/rocketpool-cli/wallet/purge.go b/rocketpool-cli/wallet/purge.go index 1c68ea3c8..bff79d8da 100644 --- a/rocketpool-cli/wallet/purge.go +++ b/rocketpool-cli/wallet/purge.go @@ -15,7 +15,7 @@ func purge(c *cli.Context) error { rp := rocketpool.NewClientFromCtx(c) defer rp.Close() - if !promptcli.Confirm(fmt.Sprintf("%sWARNING: This will delete your node wallet, all of your validator keys (including externally-generated ones in the 'custom-keys' folder), and restart your Docker containers.\nYou will NO LONGER be able to attest with this machine anymore until you recover your wallet or initialize a new one.\n\nYou MUST have your node wallet's mnemonic recorded before running this, or you will lose access to your node wallet and your validators forever!\n\n%sDo you want to continue?", colorRed, colorReset)) { + if !promptcli.Confirm("%sWARNING: This will delete your node wallet, all of your validator keys (including externally-generated ones in the 'custom-keys' folder), and restart your Docker containers.\nYou will NO LONGER be able to attest with this machine anymore until you recover your wallet or initialize a new one.\n\nYou MUST have your node wallet's mnemonic recorded before running this, or you will lose access to your node wallet and your validators forever!\n\n%sDo you want to continue?", colorRed, colorReset) { fmt.Println("Cancelled.") return nil } diff --git a/shared/services/config/rocket-pool-config.go b/shared/services/config/rocket-pool-config.go index 552f835b5..af8bcfd89 100644 --- a/shared/services/config/rocket-pool-config.go +++ b/shared/services/config/rocket-pool-config.go @@ -1497,7 +1497,7 @@ func (cfg *RocketPoolConfig) ConfirmUpdateSuggestedSettings() { cfg.ConsensusCommon.SuggestedBlockGasLimit.Value = "" } if blockGasLimit < coreDevsSuggestedGasLimit { - if prompt.Confirm(fmt.Sprintf("Your consensus block gas limit setting is currently '%d' . The maintainers suggest changing it to use the updated consensus client value. Would you like to update your setting?", blockGasLimit)) { + if prompt.Confirm("Your consensus block gas limit setting is currently '%d' . The maintainers suggest changing it to use the updated consensus client value. Would you like to update your setting?", blockGasLimit) { cfg.ConsensusCommon.SuggestedBlockGasLimit.Value = "" } } @@ -1510,7 +1510,7 @@ func (cfg *RocketPoolConfig) ConfirmUpdateSuggestedSettings() { cfg.ExecutionCommon.SuggestedBlockGasLimit.Value = "" } if blockGasLimit < coreDevsSuggestedGasLimit { - if prompt.Confirm(fmt.Sprintf("Your execution block gas limit setting is currently '%d' . The maintainers suggest changing it to use the updated consensus client value. Would you like to update your setting?", blockGasLimit)) { + if prompt.Confirm("Your execution block gas limit setting is currently '%d' . The maintainers suggest changing it to use the updated consensus client value. Would you like to update your setting?", blockGasLimit) { cfg.ExecutionCommon.SuggestedBlockGasLimit.Value = "" } } diff --git a/shared/utils/cli/prompt/prompt.go b/shared/utils/cli/prompt/prompt.go index aa7b34520..f749b1692 100644 --- a/shared/utils/cli/prompt/prompt.go +++ b/shared/utils/cli/prompt/prompt.go @@ -37,13 +37,15 @@ func Prompt(initialPrompt string, expectedFormat string, incorrectFormatPrompt s } // Prompt for confirmation -func Confirm(initialPrompt string) bool { +func Confirm(fmtStr string, args ...any) bool { + initialPrompt := fmt.Sprintf(fmtStr, args...) response := Prompt(fmt.Sprintf("%s [y/n]", initialPrompt), "(?i)^(y|yes|n|no)$", "Please answer 'y' or 'n'") return (strings.ToLower(response[:1]) == "y") } // Prompt for 'I agree' confirmation (used on important questions to avoid a quick 'y' response from the user) -func ConfirmWithIAgree(initialPrompt string) bool { +func ConfirmWithIAgree(fmtStr string, args ...any) bool { + initialPrompt := fmt.Sprintf(fmtStr, args...) response := Prompt(fmt.Sprintf("%s [Type 'I agree' or 'n']", initialPrompt), "(?i)^(i agree|n|no)$", "Please answer 'I agree' or 'n'") return (len(response) == 7 && strings.ToLower(response[:7]) == "i agree") } @@ -79,7 +81,7 @@ func Select(initialPrompt string, options []string) (int, string) { // Prompts the user to verify that there is nobody looking over their shoulder before printing sensitive information. func ConfirmSecureSession(warning string) bool { - if !Confirm(fmt.Sprintf("%s%s%s\nAre you sure you want to continue?", colorYellow, warning, colorReset)) { + if !Confirm("%s%s%s\nAre you sure you want to continue?", colorYellow, warning, colorReset) { fmt.Println("Cancelled.") return false } diff --git a/shared/utils/cli/utils.go b/shared/utils/cli/utils.go index 7677efbac..2b921fb44 100644 --- a/shared/utils/cli/utils.go +++ b/shared/utils/cli/utils.go @@ -16,6 +16,26 @@ const colorGreen string = "\033[32m" const colorYellow string = "\033[33m" const colorLightBlue string = "\033[36m" +func Red(msg string) string { + return color(colorRed, msg) +} + +func Green(msg string) string { + return color(colorGreen, msg) +} + +func Yellow(msg string) string { + return color(colorYellow, msg) +} + +func LightBlue(msg string) string { + return color(colorLightBlue, msg) +} + +func color(color, msg string) string { + return fmt.Sprintf("%s%s%s", color, msg, colorReset) +} + // Print a TX's details to the console. func PrintTransactionHash(rp *rocketpool.Client, hash common.Hash) {