diff --git a/bindings/rewards/rewards.go b/bindings/rewards/rewards.go index 1e5264adb..051542e5c 100644 --- a/bindings/rewards/rewards.go +++ b/bindings/rewards/rewards.go @@ -818,6 +818,150 @@ func getMainnetIntervalRewardsEvent(rp *rocketpool.RocketPool, index uint64) (Re intervalEndTime = time.Unix(1746682539, 0) submissionTime = time.Unix(1746691523, 0) userETH.SetString("38934754761348367759", 10) + case 36: + treasuryRPL.SetString("22048941282103056576253", 10) + trustedNodeRPL.SetString("2004449207463914234114", 10) + nodeRPL.SetString("56124577808989598554500", 10) + executionBlock = big.NewInt(22636374) + consensusBlock = big.NewInt(11856479) + intervalsPassed = big.NewInt(1) + merkleRoot = common.HexToHash("0x704c7c2f6faeb97b20535a9a325e9ba573ec066ee579853b3e94b175114a8fd7") + intervalStartTime = time.Unix(1746682539, 0) + intervalEndTime = time.Unix(1749101739, 0) + submissionTime = time.Unix(1749113279, 0) + nodeETH.SetString("50039863506253385959", 10) + userETH.SetString("57244908435972245571", 10) + case 37: + treasuryRPL.SetString("22131620846710572152925", 10) + trustedNodeRPL.SetString("2011965531519142922898", 10) + nodeRPL.SetString("56335034882536001840574", 10) + nodeETH.SetString("45418705066756834715", 10) + executionBlock = big.NewInt(22836652) + consensusBlock = big.NewInt(12058079) + intervalsPassed = big.NewInt(1) + merkleRoot = common.HexToHash("0xf4db744c50762a7ae1b19ee26120a582207eb1c535614711aae4cc5c598e42cf") + intervalStartTime = time.Unix(1749101739, 0) + intervalEndTime = time.Unix(1751520939, 0) + submissionTime = time.Unix(1751532611, 0) + userETH.SetString("48318015461156177248", 10) + case 38: + treasuryRPL.SetString("22214610444816577609208", 10) + trustedNodeRPL.SetString("2019510040437870691659", 10) + nodeRPL.SetString("56546281132260379365673", 10) + nodeETH.SetString("40700127824685134045", 10) + executionBlock = big.NewInt(23037044) + consensusBlock = big.NewInt(12259679) + intervalsPassed = big.NewInt(1) + merkleRoot = common.HexToHash("0xf7809e999791fb6c73712c7d281624020ba773dc144fdfbb41c86b2e3cbb42fd") + intervalStartTime = time.Unix(1751520939, 0) + intervalEndTime = time.Unix(1753940139, 0) + submissionTime = time.Unix(1753948367, 0) + userETH.SetString("40528725716465757725", 10) + case 39: + treasuryRPL.SetString("22297911238990936999935", 10) + trustedNodeRPL.SetString("2027082839908266999911", 10) + nodeRPL.SetString("56758319517431475996754", 10) + nodeETH.SetString("34921409718655333629", 10) + executionBlock = big.NewInt(23237567) + consensusBlock = big.NewInt(12461279) + intervalsPassed = big.NewInt(1) + merkleRoot = common.HexToHash("0xec51162c8af79d86e4b8f6546ec0e1ec3b4172b12574893e938c4f5bdd408efe") + intervalStartTime = time.Unix(1753940139, 0) + intervalEndTime = time.Unix(1756359339, 0) + submissionTime = time.Unix(1756395407, 0) + userETH.SetString("31594532680318853963", 10) + case 40: + // {"status":"success","error":"","found":true,"index":"40","executionBlock":"23438005","consensusBlock":"12662879","merkleRoot":"0x2ad908aa47f988d09dd9884c8026e6213262e231bab0d5051eedb2bef6aefe1e","intervalsPassed":"1","treasuryRPL":"22381524396162942297937","trustedNodeRPL":["2034684036014812936091"],"nodeRPL":["56971153008414762209929"],"nodeETH":["24246940457789627532"],"userETH":"13888515305764133572","intervalStartTime":1756359339,"intervalEndTime":1758778539,"submissionTime":1758785783} + treasuryRPL.SetString("22381524396162942297937", 10) + trustedNodeRPL.SetString("2034684036014812936091", 10) + nodeRPL.SetString("56971153008414762209929", 10) + nodeETH.SetString("24246940457789627532", 10) + executionBlock = big.NewInt(23438005) + consensusBlock = big.NewInt(12662879) + intervalsPassed = big.NewInt(1) + merkleRoot = common.HexToHash("0x2ad908aa47f988d09dd9884c8026e6213262e231bab0d5051eedb2bef6aefe1e") + intervalStartTime = time.Unix(1756359339, 0) + intervalEndTime = time.Unix(1758778539, 0) + submissionTime = time.Unix(1758785783, 0) + userETH.SetString("13888515305764133572", 10) + case 41: + treasuryRPL.SetString("22465451087637660464639", 10) + trustedNodeRPL.SetString("2042313735239787314880", 10) + nodeRPL.SetString("57184784586714044816063", 10) + nodeETH.SetString("43676270282606810107", 10) + executionBlock = big.NewInt(23638162) + consensusBlock = big.NewInt(12864479) + intervalsPassed = big.NewInt(1) + merkleRoot = common.HexToHash("0xe8af8737484cfd3d3fd5106ef189333e92f9bbc2de0ac057f4c01c473b2ec958") + intervalStartTime = time.Unix(1758778539, 0) + intervalEndTime = time.Unix(1761197739, 0) + submissionTime = time.Unix(1761205211, 0) + userETH.SetString("47268078777290226308", 10) + case 42: + treasuryRPL.SetString("22549692489112341819332", 10) + trustedNodeRPL.SetString("2049972044464758347124", 10) + nodeRPL.SetString("57399217245013233718952", 10) + nodeETH.SetString("25631914712861974454", 10) + executionBlock = big.NewInt(23838215) + consensusBlock = big.NewInt(13066079) + intervalsPassed = big.NewInt(1) + merkleRoot = common.HexToHash("0x9f8c89596b48d377279bf703444a2e0cd5e98ac4cc0f5c490324c394c1ba3ce8") + intervalStartTime = time.Unix(1761197739, 0) + intervalEndTime = time.Unix(1763616939, 0) + submissionTime = time.Unix(1763642831, 0) + userETH.SetString("17561894202841328207", 10) + case 43: + treasuryRPL.SetString("22634249780692889936981", 10) + trustedNodeRPL.SetString("2057659070972080903284", 10) + nodeRPL.SetString("57614453987218265291225", 10) + nodeETH.SetString("18947687367286040081", 10) + executionBlock = big.NewInt(24037441) + consensusBlock = big.NewInt(13267679) + intervalsPassed = big.NewInt(1) + merkleRoot = common.HexToHash("0xa98c94badfa30d41fcde8a3c5ccdadadbe441e43883919567b2d45682e476ca3") + intervalStartTime = time.Unix(1763616939, 0) + intervalEndTime = time.Unix(1766036139, 0) + submissionTime = time.Unix(1766046599, 0) + userETH.SetString("8352566574518930988", 10) + case 44: + treasuryRPL.SetString("22719124146910393305039", 10) + trustedNodeRPL.SetString("2065374922446399391296", 10) + nodeRPL.SetString("57830497828499182955594", 10) + nodeETH.SetString("15367476931278801422", 10) + executionBlock = big.NewInt(24238059) + consensusBlock = big.NewInt(13469279) + intervalsPassed = big.NewInt(1) + merkleRoot = common.HexToHash("0x72ed38107b2b6c1a0469800af741c04adf5563aebe5a0ae5d77fb9b2354c64a5") + intervalStartTime = time.Unix(1766036139, 0) + intervalEndTime = time.Unix(1768455339, 0) + submissionTime = time.Unix(1768461851, 0) + userETH.SetString("4223474559072201135", 10) + case 45: + treasuryRPL.SetString("22804316776737718971210", 10) + trustedNodeRPL.SetString("2073119706976156270036", 10) + nodeRPL.SetString("58047351795332375560374", 10) + nodeETH.SetString("28550894583322805236", 10) + executionBlock = big.NewInt(24438645) + consensusBlock = big.NewInt(13670879) + intervalsPassed = big.NewInt(1) + merkleRoot = common.HexToHash("0x97dc8f589c86c3650a96568ab05c08a9e160aec7eb405e35ec2e62c6e1af559c") + intervalStartTime = time.Unix(1768455339, 0) + intervalEndTime = time.Unix(1770874539, 0) + submissionTime = time.Unix(1770894827, 0) + userETH.SetString("22178758316567204991", 10) + case 46: + treasuryRPL.SetString("22889828863606168413868", 10) + trustedNodeRPL.SetString("2080893533055106219373", 10) + nodeRPL.SetString("58265018925542974141956", 10) + nodeETH.SetString("19997007660595265346", 10) + executionBlock = big.NewInt(24639334) + consensusBlock = big.NewInt(13872479) + intervalsPassed = big.NewInt(1) + merkleRoot = common.HexToHash("0x8cb45bcefd498b8788e6291c4dc086694c85b495fb60e9d5b047e7b921929d48") + intervalStartTime = time.Unix(1770874539, 0) + intervalEndTime = time.Unix(1773293739, 0) + submissionTime = time.Unix(1773299819, 0) + userETH.SetString("12369109587853762785", 10) default: return RewardsEvent{}, false, nil } diff --git a/bindings/utils/eth/units.go b/bindings/utils/eth/units.go index 9d5407eb7..4b5ec450f 100644 --- a/bindings/utils/eth/units.go +++ b/bindings/utils/eth/units.go @@ -39,6 +39,9 @@ func EthToWei(eth float64) *big.Int { // Convert wei to gigawei func WeiToGwei(wei *big.Int) float64 { + if wei == nil { + return 0 + } var weiFloat big.Float var gwei big.Float weiFloat.SetInt(wei) diff --git a/bindings/utils/wait.go b/bindings/utils/wait.go index 7a9649c42..f68ae61d9 100644 --- a/bindings/utils/wait.go +++ b/bindings/utils/wait.go @@ -3,7 +3,6 @@ package utils import ( "context" "errors" - "fmt" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -12,32 +11,30 @@ import ( "github.com/rocket-pool/smartnode/bindings/rocketpool" ) -// Wait for a transaction to get mined -func WaitForTransaction(client rocketpool.ExecutionClient, hash common.Hash) (*types.Receipt, error) { - +// Wait for a transaction to get included, respecting the provided context for cancellation. +// The transaction lookup retries indefinitely (with 1-second pauses) until found or ctx is done. +func WaitForTransactionWithContext(ctx context.Context, client rocketpool.ExecutionClient, hash common.Hash) (*types.Receipt, error) { var tx *types.Transaction - var err error - // Get the transaction from its hash, retrying for 30 sec if it wasn't found - for i := 0; i < 30; i++ { - if i == 29 { - return nil, fmt.Errorf("Transaction not found after 30 seconds.") + // Get the transaction from its hash, retrying until found or ctx is cancelled. + for { + var err error + tx, _, err = client.TransactionByHash(ctx, hash) + if err == nil { + break } - - tx, _, err = client.TransactionByHash(context.Background(), hash) - if err != nil { - if err.Error() == "not found" { - time.Sleep(1 * time.Second) - continue - } + if err.Error() != "not found" { return nil, err - } else { - break + } + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(1 * time.Second): } } // Wait for transaction to be mined - txReceipt, err := bind.WaitMined(context.Background(), client, tx) + txReceipt, err := bind.WaitMined(ctx, client, tx) if err != nil { return nil, err } @@ -47,6 +44,10 @@ func WaitForTransaction(client rocketpool.ExecutionClient, hash common.Hash) (*t return txReceipt, errors.New("Transaction failed with status 0") } - // Return return txReceipt, nil } + +// Wait for a transaction to get mined +func WaitForTransaction(client rocketpool.ExecutionClient, hash common.Hash) (*types.Receipt, error) { + return WaitForTransactionWithContext(context.Background(), client, hash) +} diff --git a/rocketpool-cli/megapool/commands.go b/rocketpool-cli/megapool/commands.go index 4ec3fcac1..cc4ba4a12 100644 --- a/rocketpool-cli/megapool/commands.go +++ b/rocketpool-cli/megapool/commands.go @@ -236,7 +236,7 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { Name: "yes", Usage: "Automatically confirm the action", }, - &cli.StringFlag{ + &cli.Uint64Flag{ Name: "validator-id", Usage: "The validator id to exit", }, @@ -277,7 +277,7 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { Name: "yes", Usage: "Automatically confirm the action", }, - &cli.StringFlag{ + &cli.Uint64Flag{ Name: "validator-id", Usage: "The validator id to exit", }, @@ -318,7 +318,7 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { Name: "yes", Usage: "Automatically confirm the action", }, - &cli.StringFlag{ + &cli.Uint64Flag{ Name: "validator-id", Usage: "The validator id for which the exit is being notified", }, @@ -359,7 +359,7 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { Name: "yes", Usage: "Automatically confirm the action", }, - &cli.StringFlag{ + &cli.Uint64Flag{ Name: "validator-id", Usage: "The validator id for which the final balance is being notified", }, @@ -409,33 +409,35 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) { return distribute(c.Bool("yes")) }, }, - // Add set-use-latest-delegate command { Name: "set-use-latest-delegate", Aliases: []string{"l"}, Usage: "Set the megapool to always use the latest delegate", - UsageText: "rocketpool megapool set-use-latest-delegate use-latest-delegate", - + UsageText: "rocketpool megapool set-use-latest-delegate", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "use-latest-delegate", + Usage: "Enable (true) or disable (false) automatic using the latest delegate; omit to be prompted based on the current setting", + }, + &cli.BoolFlag{ + Name: "yes", + Usage: "Automatically confirm the action", + }, + }, Action: func(ctx context.Context, c *cli.Command) error { - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { + if err := cliutils.ValidateArgCount(c, 0); err != nil { return err } - useLatest, err := cliutils.ValidateBool("use-latest-delegate", c.Args().Get(0)) - if err != nil { - return err + var useLatest *bool + if c.IsSet("use-latest-delegate") { + val := c.Bool("use-latest-delegate") + useLatest = &val } return setUseLatestDelegateMegapool(useLatest, c.Bool("yes")) }, - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "yes", - Usage: "Automatically confirm the action", - }, - }, }, }, }) diff --git a/rocketpool-cli/megapool/delegate.go b/rocketpool-cli/megapool/delegate.go index ae86a7ee4..c5d4cb531 100644 --- a/rocketpool-cli/megapool/delegate.go +++ b/rocketpool-cli/megapool/delegate.go @@ -9,7 +9,7 @@ import ( "github.com/rocket-pool/smartnode/shared/utils/cli/prompt" ) -func setUseLatestDelegateMegapool(setting bool, yes bool) error { +func setUseLatestDelegateMegapool(setting *bool, yes bool) error { // Get RP client rp, err := rocketpool.NewClient().WithReady() if err != nil { @@ -29,26 +29,49 @@ func setUseLatestDelegateMegapool(setting bool, yes bool) error { return nil } + // If no flag was provided, prompt the user based on the current setting + if setting == nil { + currentSetting := status.Megapool.UseLatestDelegate + var desired bool + if currentSetting { + fmt.Println("Your megapool currently has automatic delegate upgrades enabled.") + if !prompt.Confirm("Would you like to disable automatic delegate upgrades?") { + fmt.Println("No changes made.") + return nil + } + desired = false + } else { + fmt.Println("Your megapool currently has automatic delegate upgrades disabled.") + if !prompt.Confirm("Would you like to enable automatic delegate upgrades?") { + fmt.Println("No changes made.") + return nil + } + desired = true + } + setting = &desired + } + megapoolAddress := status.Megapool.Address // Print message we're updating the setting - if setting == true { + if *setting { fmt.Printf("Updating the use-latest-delegate setting for megapool %s to enabled...\n", megapoolAddress.Hex()) } else { fmt.Printf("Updating the use-latest-delegate setting for megapool %s to disabled...\n", megapoolAddress.Hex()) } // Get the gas estimate - canResponse, err := rp.CanSetUseLatestDelegateMegapool(megapoolAddress, setting) + canResponse, err := rp.CanSetUseLatestDelegateMegapool(megapoolAddress, *setting) if err != nil { return fmt.Errorf("error checking if megapool %s could have its use-latest-delegate flag changed: %w", megapoolAddress.Hex(), err) } - if canResponse.MatchesCurrentSetting == true { - if setting == true { + if canResponse.MatchesCurrentSetting { + if *setting { fmt.Printf("Could not enable use-latest-delegate on the node's megapool, the setting is already enabled.") } else { fmt.Printf("Could not disable use-latest-delegate on the node's megapool, the setting is already disabled.") } + fmt.Println() return nil } @@ -65,7 +88,7 @@ func setUseLatestDelegateMegapool(setting bool, yes bool) error { } // Update flag - response, err := rp.SetUseLatestDelegateMegapool(megapoolAddress, setting) + response, err := rp.SetUseLatestDelegateMegapool(megapoolAddress, *setting) if err != nil { fmt.Printf("Could not set use latest delegate for megapool %s: %s. \n", megapoolAddress.Hex(), err) return nil diff --git a/rocketpool-cli/rocketpool-cli.go b/rocketpool-cli/rocketpool-cli.go index d3edfcdab..e3d883697 100644 --- a/rocketpool-cli/rocketpool-cli.go +++ b/rocketpool-cli/rocketpool-cli.go @@ -202,6 +202,7 @@ func main() { } if len(response.Alerts) > 0 { + fmt.Println() color.YellowPrintln("=== Alerts ===") for i, alert := range response.Alerts { fmt.Println(alert.ColorString()) diff --git a/rocketpool/api/api.go b/rocketpool/api/api.go index a8dc437cf..778f64ec1 100644 --- a/rocketpool/api/api.go +++ b/rocketpool/api/api.go @@ -1,116 +1 @@ package api - -import ( - "context" - "net/http" - - "github.com/ethereum/go-ethereum/common" - "github.com/rocket-pool/smartnode/rocketpool/api/debug" - "github.com/rocket-pool/smartnode/rocketpool/api/megapool" - "github.com/rocket-pool/smartnode/rocketpool/api/pdao" - "github.com/rocket-pool/smartnode/rocketpool/api/security" - "github.com/rocket-pool/smartnode/rocketpool/api/upgrade" - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/bindings/utils" - "github.com/rocket-pool/smartnode/rocketpool/api/auction" - "github.com/rocket-pool/smartnode/rocketpool/api/minipool" - "github.com/rocket-pool/smartnode/rocketpool/api/network" - "github.com/rocket-pool/smartnode/rocketpool/api/node" - "github.com/rocket-pool/smartnode/rocketpool/api/odao" - "github.com/rocket-pool/smartnode/rocketpool/api/queue" - apiservice "github.com/rocket-pool/smartnode/rocketpool/api/service" - "github.com/rocket-pool/smartnode/rocketpool/api/wallet" - "github.com/rocket-pool/smartnode/shared/services" - apitypes "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -const ( - MaxConcurrentEth1Requests = 200 -) - -// Waits for an auction transaction -func waitForTransaction(c *cli.Command, hash common.Hash) (*apitypes.APIResponse, error) { - - rp, err := services.GetRocketPool(c) - if err != nil { - return nil, err - } - - // Response - response := apitypes.APIResponse{} - _, err = utils.WaitForTransaction(rp.Client, hash) - if err != nil { - return nil, err - } - - // Return response - return &response, nil - -} - -// Register commands -func RegisterCommands(app *cli.Command, name string, aliases []string) { - - // CLI command - command := cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Run Rocket Pool API commands", - Commands: []*cli.Command{}, - } - - // Don't show help message for api errors because of JSON serialisation - command.OnUsageError = func(ctx context.Context, c *cli.Command, err error, isSubcommand bool) error { - return err - } - - // Register subcommands - auction.RegisterSubcommands(&command, "auction", []string{"a"}) - megapool.RegisterSubcommands(&command, "megapool", []string{"g"}) - minipool.RegisterSubcommands(&command, "minipool", []string{"m"}) - megapool.RegisterSubcommands(&command, "megapool", []string{"g"}) - network.RegisterSubcommands(&command, "network", []string{"e"}) - node.RegisterSubcommands(&command, "node", []string{"n"}) - odao.RegisterSubcommands(&command, "odao", []string{"o"}) - pdao.RegisterSubcommands(&command, "pdao", []string{"p"}) - queue.RegisterSubcommands(&command, "queue", []string{"q"}) - security.RegisterSubcommands(&command, "security", []string{"c"}) - apiservice.RegisterSubcommands(&command, "service", []string{"s"}) - wallet.RegisterSubcommands(&command, "wallet", []string{"w"}) - upgrade.RegisterSubcommands(&command, "upgrade", []string{"u"}) - debug.RegisterSubcommands(&command, "debug", []string{"d"}) - - // Append a general wait-for-transaction command to support async operations - command.Commands = append(command.Commands, &cli.Command{ - Name: "wait", - Aliases: []string{"t"}, - Usage: "Wait for a transaction to complete", - UsageText: "rocketpool api wait tx-hash", - Action: func(ctx context.Context, c *cli.Command) error { - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - hash, err := cliutils.ValidateTxHash("tx-hash", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(waitForTransaction(c, hash)) - return nil - }, - }) - - // Register CLI command - app.Commands = append(app.Commands, &command) - - // The daemon makes a large number of concurrent RPC requests to the Eth1 client - // The HTTP transport is set to cache connections for future re-use equal to the maximum expected number of concurrent requests - // This prevents issues related to memory consumption and address allowance from repeatedly opening and closing connections - http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = MaxConcurrentEth1Requests - -} diff --git a/rocketpool/api/auction/bid-lot.go b/rocketpool/api/auction/bid-lot.go index 3aa9485d6..3dd57714c 100644 --- a/rocketpool/api/auction/bid-lot.go +++ b/rocketpool/api/auction/bid-lot.go @@ -1,9 +1,9 @@ package auction import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/auction" "github.com/rocket-pool/smartnode/bindings/settings/protocol" "github.com/urfave/cli/v3" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canBidOnLot(c *cli.Command, lotIndex uint64, amountWei *big.Int) (*api.CanBidOnLotResponse, error) { @@ -99,7 +98,7 @@ func canBidOnLot(c *cli.Command, lotIndex uint64, amountWei *big.Int) (*api.CanB } -func bidOnLot(c *cli.Command, lotIndex uint64, amountWei *big.Int) (*api.BidOnLotResponse, error) { +func bidOnLot(c *cli.Command, lotIndex uint64, amountWei *big.Int, opts *bind.TransactOpts) (*api.BidOnLotResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -108,10 +107,6 @@ func bidOnLot(c *cli.Command, lotIndex uint64, amountWei *big.Int) (*api.BidOnLo if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -120,19 +115,8 @@ func bidOnLot(c *cli.Command, lotIndex uint64, amountWei *big.Int) (*api.BidOnLo // Response response := api.BidOnLotResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } opts.Value = amountWei - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Bid on lot hash, err := auction.PlaceBid(rp, lotIndex, opts) if err != nil { diff --git a/rocketpool/api/auction/claim-lot.go b/rocketpool/api/auction/claim-lot.go index fa17fbe20..99c1a4778 100644 --- a/rocketpool/api/auction/claim-lot.go +++ b/rocketpool/api/auction/claim-lot.go @@ -1,16 +1,15 @@ package auction import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/auction" "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canClaimFromLot(c *cli.Command, lotIndex uint64) (*api.CanClaimFromLotResponse, error) { @@ -92,7 +91,7 @@ func canClaimFromLot(c *cli.Command, lotIndex uint64) (*api.CanClaimFromLotRespo } -func claimFromLot(c *cli.Command, lotIndex uint64) (*api.ClaimFromLotResponse, error) { +func claimFromLot(c *cli.Command, lotIndex uint64, opts *bind.TransactOpts) (*api.ClaimFromLotResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -101,10 +100,6 @@ func claimFromLot(c *cli.Command, lotIndex uint64) (*api.ClaimFromLotResponse, e if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -113,18 +108,6 @@ func claimFromLot(c *cli.Command, lotIndex uint64) (*api.ClaimFromLotResponse, e // Response response := api.ClaimFromLotResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Claim from lot hash, err := auction.ClaimBid(rp, lotIndex, opts) if err != nil { diff --git a/rocketpool/api/auction/commands.go b/rocketpool/api/auction/commands.go deleted file mode 100644 index 5f6b72d7d..000000000 --- a/rocketpool/api/auction/commands.go +++ /dev/null @@ -1,235 +0,0 @@ -package auction - -import ( - "context" - - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage Rocket Pool RPL auctions", - Commands: []*cli.Command{ - - { - Name: "status", - Aliases: []string{"s"}, - Usage: "Get RPL auction status", - UsageText: "rocketpool api auction status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getStatus(c)) - return nil - - }, - }, - - { - Name: "lots", - Aliases: []string{"l"}, - Usage: "Get RPL lots for auction", - UsageText: "rocketpool api auction lots", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getLots(c)) - return nil - - }, - }, - - { - Name: "can-create-lot", - Usage: "Check whether the node can create a new lot", - UsageText: "rocketpool api auction can-create-lot", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canCreateLot(c)) - return nil - - }, - }, - { - Name: "create-lot", - Aliases: []string{"t"}, - Usage: "Create a new lot", - UsageText: "rocketpool api auction create-lot", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(createLot(c)) - return nil - - }, - }, - - { - Name: "can-bid-lot", - Usage: "Check whether the node can bid on a lot", - UsageText: "rocketpool api auction can-bid-lot lot-id amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - lotIndex, err := cliutils.ValidateUint("lot ID", c.Args().Get(0)) - if err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("bid amount", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canBidOnLot(c, lotIndex, amountWei)) - return nil - - }, - }, - { - Name: "bid-lot", - Aliases: []string{"b"}, - Usage: "Bid on a lot", - UsageText: "rocketpool api auction bid-lot lot-id amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - lotIndex, err := cliutils.ValidateUint("lot ID", c.Args().Get(0)) - if err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("bid amount", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(bidOnLot(c, lotIndex, amountWei)) - return nil - - }, - }, - - { - Name: "can-claim-lot", - Usage: "Check whether the node can claim RPL from a lot", - UsageText: "rocketpool api auction can-claim-lot lot-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - lotIndex, err := cliutils.ValidateUint("lot ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canClaimFromLot(c, lotIndex)) - return nil - - }, - }, - { - Name: "claim-lot", - Aliases: []string{"c"}, - Usage: "Claim RPL from a lot", - UsageText: "rocketpool api auction claim-lot lot-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - lotIndex, err := cliutils.ValidateUint("lot ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(claimFromLot(c, lotIndex)) - return nil - - }, - }, - - { - Name: "can-recover-lot", - Usage: "Check whether the node can recover unclaimed RPL from a lot", - UsageText: "rocketpool api auction can-recover-lot lot-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - lotIndex, err := cliutils.ValidateUint("lot ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canRecoverRplFromLot(c, lotIndex)) - return nil - - }, - }, - { - Name: "recover-lot", - Aliases: []string{"r"}, - Usage: "Recover unclaimed RPL from a lot (returning it to the auction contract)", - UsageText: "rocketpool api auction recover-lot lot-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - lotIndex, err := cliutils.ValidateUint("lot ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(recoverRplFromLot(c, lotIndex)) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/auction/create-lot.go b/rocketpool/api/auction/create-lot.go index 9752f1d9a..63baceb3d 100644 --- a/rocketpool/api/auction/create-lot.go +++ b/rocketpool/api/auction/create-lot.go @@ -1,8 +1,7 @@ package auction import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/auction" "github.com/rocket-pool/smartnode/bindings/settings/protocol" "github.com/urfave/cli/v3" @@ -10,7 +9,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canCreateLot(c *cli.Command) (*api.CanCreateLotResponse, error) { @@ -79,7 +77,7 @@ func canCreateLot(c *cli.Command) (*api.CanCreateLotResponse, error) { } -func createLot(c *cli.Command) (*api.CreateLotResponse, error) { +func createLot(c *cli.Command, opts *bind.TransactOpts) (*api.CreateLotResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -88,10 +86,6 @@ func createLot(c *cli.Command) (*api.CreateLotResponse, error) { if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -100,18 +94,6 @@ func createLot(c *cli.Command) (*api.CreateLotResponse, error) { // Response response := api.CreateLotResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Create lot lotIndex, hash, err := auction.CreateLot(rp, opts) if err != nil { diff --git a/rocketpool/api/auction/recover-lot.go b/rocketpool/api/auction/recover-lot.go index 6fe548ac4..6c211bf3d 100644 --- a/rocketpool/api/auction/recover-lot.go +++ b/rocketpool/api/auction/recover-lot.go @@ -1,16 +1,15 @@ package auction import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/auction" "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canRecoverRplFromLot(c *cli.Command, lotIndex uint64) (*api.CanRecoverRPLFromLotResponse, error) { @@ -97,7 +96,7 @@ func canRecoverRplFromLot(c *cli.Command, lotIndex uint64) (*api.CanRecoverRPLFr } -func recoverRplFromLot(c *cli.Command, lotIndex uint64) (*api.RecoverRPLFromLotResponse, error) { +func recoverRplFromLot(c *cli.Command, lotIndex uint64, opts *bind.TransactOpts) (*api.RecoverRPLFromLotResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -106,10 +105,6 @@ func recoverRplFromLot(c *cli.Command, lotIndex uint64) (*api.RecoverRPLFromLotR if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -118,18 +113,6 @@ func recoverRplFromLot(c *cli.Command, lotIndex uint64) (*api.RecoverRPLFromLotR // Response response := api.RecoverRPLFromLotResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Recover unclaimed RPL from lot hash, err := auction.RecoverUnclaimedRPL(rp, lotIndex, opts) if err != nil { diff --git a/rocketpool/api/auction/routes.go b/rocketpool/api/auction/routes.go new file mode 100644 index 000000000..b5e0ab268 --- /dev/null +++ b/rocketpool/api/auction/routes.go @@ -0,0 +1,140 @@ +package auction + +import ( + "fmt" + "math/big" + "net/http" + "strconv" + + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/shared/services" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +// RegisterRoutes registers the auction module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/auction/status", func(w http.ResponseWriter, r *http.Request) { + resp, err := getStatus(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/auction/lots", func(w http.ResponseWriter, r *http.Request) { + resp, err := getLots(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/auction/can-create-lot", func(w http.ResponseWriter, r *http.Request) { + resp, err := canCreateLot(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/auction/create-lot", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := createLot(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/auction/can-bid-lot", func(w http.ResponseWriter, r *http.Request) { + lotIndex, amountWei, err := parseLotIndexAndAmount(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canBidOnLot(c, lotIndex, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/auction/bid-lot", func(w http.ResponseWriter, r *http.Request) { + lotIndex, amountWei, err := parseLotIndexAndAmount(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := bidOnLot(c, lotIndex, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/auction/can-claim-lot", func(w http.ResponseWriter, r *http.Request) { + lotIndex, err := parseLotIndex(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canClaimFromLot(c, lotIndex) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/auction/claim-lot", func(w http.ResponseWriter, r *http.Request) { + lotIndex, err := parseLotIndex(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := claimFromLot(c, lotIndex, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/auction/can-recover-lot", func(w http.ResponseWriter, r *http.Request) { + lotIndex, err := parseLotIndex(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canRecoverRplFromLot(c, lotIndex) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/auction/recover-lot", func(w http.ResponseWriter, r *http.Request) { + lotIndex, err := parseLotIndex(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := recoverRplFromLot(c, lotIndex, opts) + apiutils.WriteResponse(w, resp, err) + }) +} + +func parseLotIndex(r *http.Request) (uint64, error) { + raw := r.URL.Query().Get("lotIndex") + if raw == "" { + raw = r.FormValue("lotIndex") + } + return strconv.ParseUint(raw, 10, 64) +} + +func parseLotIndexAndAmount(r *http.Request) (uint64, *big.Int, error) { + lotIndex, err := parseLotIndex(r) + if err != nil { + return 0, nil, err + } + raw := r.URL.Query().Get("amountWei") + if raw == "" { + raw = r.FormValue("amountWei") + } + amountWei, ok := new(big.Int).SetString(raw, 10) + if !ok { + return 0, nil, fmt.Errorf("invalid amountWei: %s", raw) + } + return lotIndex, amountWei, nil +} diff --git a/rocketpool/api/debug/commands.go b/rocketpool/api/debug/commands.go deleted file mode 100644 index c1dddf7ef..000000000 --- a/rocketpool/api/debug/commands.go +++ /dev/null @@ -1,100 +0,0 @@ -package debug - -import ( - "context" - "fmt" - - "github.com/urfave/cli/v3" - - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Debugging and troubleshooting commands", - Commands: []*cli.Command{ - - { - Name: "export-validators", - Aliases: []string{"x"}, - Usage: "Exports a TSV file of validators", - UsageText: "rocketpool api debug export-validators", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Export TSV of validators - if err := ExportValidators(c); err != nil { - fmt.Printf("An error occurred: %s\n", err) - } - return nil - - }, - }, - { - Name: "get-beacon-state", - Aliases: []string{"b"}, - Usage: "Returns the beacon state for a given slot number", - UsageText: "rocketpool api debug get-beacon-state slot-number validator-index", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - - slotNumber, err := cliutils.ValidatePositiveUint("slot number", c.Args().Get(0)) - if err != nil { - return err - } - - validatorIndex, err := cliutils.ValidatePositiveUint("validator index", c.Args().Get(1)) - if err != nil { - return err - } - - if err := getBeaconStateForSlot(c, slotNumber, validatorIndex); err != nil { - fmt.Printf("An error occurred: %s\n", err) - } - return nil - - }, - }, - { - Name: "get-withdrawal-proof", - Aliases: []string{"w"}, - Usage: "Returns a withdrawal proof for a given validator index and given slot, for the withdrawal most recent to that slot", - UsageText: "rocketpool api debug get-withdrawal-proof slot-number validator-index", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - - slotNumber, err := cliutils.ValidatePositiveUint("slot number", c.Args().Get(0)) - if err != nil { - return err - } - - validatorIndex, err := cliutils.ValidatePositiveUint("validator index", c.Args().Get(1)) - if err != nil { - return err - } - - if err := getWithdrawalProofForSlot(c, slotNumber, validatorIndex); err != nil { - fmt.Printf("An error occurred: %s\n", err) - } - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/debug/rewards-event.go b/rocketpool/api/debug/rewards-event.go new file mode 100644 index 000000000..e059f3222 --- /dev/null +++ b/rocketpool/api/debug/rewards-event.go @@ -0,0 +1,61 @@ +package debug + +import ( + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/shared/services" + rprewards "github.com/rocket-pool/smartnode/shared/services/rewards" + "github.com/rocket-pool/smartnode/shared/types/api" +) + +func getRewardsEvent(c *cli.Command, interval uint64) (*api.RewardsEventResponse, error) { + if err := services.RequireRocketStorage(c); err != nil { + return nil, err + } + rp, err := services.GetRocketPool(c) + if err != nil { + return nil, err + } + cfg, err := services.GetConfig(c) + if err != nil { + return nil, err + } + + previousRewardsPoolAddresses := cfg.Smartnode.GetPreviousRewardsPoolAddresses() + rewardsClient := rprewards.NewRewardsExecutionClient(rp) + + event, err := rewardsClient.GetRewardSnapshotEvent(previousRewardsPoolAddresses, interval, nil) + if err != nil { + return nil, err + } + + response := api.RewardsEventResponse{ + Found: true, + } + + response.Index = event.Index.String() + response.ExecutionBlock = event.ExecutionBlock.String() + response.ConsensusBlock = event.ConsensusBlock.String() + response.MerkleRoot = event.MerkleRoot.Hex() + response.IntervalsPassed = event.IntervalsPassed.String() + response.TreasuryRPL = event.TreasuryRPL.String() + response.UserETH = event.UserETH.String() + response.IntervalStartTime = event.IntervalStartTime.Unix() + response.IntervalEndTime = event.IntervalEndTime.Unix() + response.SubmissionTime = event.SubmissionTime.Unix() + + response.TrustedNodeRPL = make([]string, len(event.TrustedNodeRPL)) + for i, v := range event.TrustedNodeRPL { + response.TrustedNodeRPL[i] = v.String() + } + response.NodeRPL = make([]string, len(event.NodeRPL)) + for i, v := range event.NodeRPL { + response.NodeRPL[i] = v.String() + } + response.NodeETH = make([]string, len(event.NodeETH)) + for i, v := range event.NodeETH { + response.NodeETH[i] = v.String() + } + + return &response, nil +} diff --git a/rocketpool/api/debug/routes.go b/rocketpool/api/debug/routes.go new file mode 100644 index 000000000..b97c8e761 --- /dev/null +++ b/rocketpool/api/debug/routes.go @@ -0,0 +1,28 @@ +package debug + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/urfave/cli/v3" + + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/debug/rewards-event", func(w http.ResponseWriter, r *http.Request) { + raw := r.URL.Query().Get("interval") + if raw == "" { + apiutils.WriteErrorResponse(w, &apiutils.BadRequestError{Err: fmt.Errorf("missing required query parameter: interval")}) + return + } + interval, err := strconv.ParseUint(raw, 10, 64) + if err != nil { + apiutils.WriteErrorResponse(w, &apiutils.BadRequestError{Err: fmt.Errorf("invalid interval: %w", err)}) + return + } + resp, err := getRewardsEvent(c, interval) + apiutils.WriteResponse(w, resp, err) + }) +} diff --git a/rocketpool/api/megapool/claim-refunds.go b/rocketpool/api/megapool/claim-refunds.go index 08c5d2c73..356876510 100644 --- a/rocketpool/api/megapool/claim-refunds.go +++ b/rocketpool/api/megapool/claim-refunds.go @@ -1,15 +1,14 @@ package megapool import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canClaimRefund(c *cli.Command) (*api.CanClaimRefundResponse, error) { @@ -83,7 +82,7 @@ func canClaimRefund(c *cli.Command) (*api.CanClaimRefundResponse, error) { } -func claimRefund(c *cli.Command) (*api.ClaimRefundResponse, error) { +func claimRefund(c *cli.Command, opts *bind.TransactOpts) (*api.ClaimRefundResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -119,18 +118,6 @@ func claimRefund(c *cli.Command) (*api.ClaimRefundResponse, error) { return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Dissolve hash, err := mp.ClaimRefund(opts) if err != nil { diff --git a/rocketpool/api/megapool/commands.go b/rocketpool/api/megapool/commands.go deleted file mode 100644 index fc224f6ca..000000000 --- a/rocketpool/api/megapool/commands.go +++ /dev/null @@ -1,730 +0,0 @@ -package megapool - -import ( - "context" - - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage the node's megapool", - Commands: []*cli.Command{ - { - Name: "can-distribute-megapool", - Usage: "Check if can distribute megapool rewards", - UsageText: "rocketpool api node can-distribute-megapool", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canDistributeMegapool(c)) - return nil - - }, - }, - - { - Name: "distribute-megapool", - Usage: "Distribute megapool rewards", - UsageText: "rocketpool api node distribute-megapool", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(distributeMegapool(c)) - return nil - - }, - }, - { - Name: "status", - Aliases: []string{"s"}, - Usage: "Get the node's megapool status", - UsageText: "rocketpool api megapool status finalized-state", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get finalized state - finalizedState, err := cliutils.ValidateBool("finalized-state", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getStatus(c, finalizedState)) - return nil - - }, - }, - { - Name: "validator-map-and-balances", - Aliases: []string{"gvm"}, - Usage: "Get a map of the node's validators and beacon balances", - UsageText: "rocketpool api megapool validator-map-and-balances", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getValidatorMapAndBalances(c)) - return nil - - }, - }, - { - Name: "can-repay-debt", - Usage: "Check if we can repay the megapool debt", - UsageText: "rocketpool api megapool can-repay-debt amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get amount - amount, err := cliutils.ValidatePositiveWeiAmount("amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canRepayDebt(c, amount)) - return nil - - }, - }, - { - Name: "repay-debt", - Aliases: []string{"rd"}, - Usage: "Repay the megapool debt", - UsageText: "rocketpool api megapool repay-debt amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get amount - amount, err := cliutils.ValidatePositiveWeiAmount("amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(repayDebt(c, amount)) - return nil - - }, - }, - { - Name: "can-reduce-bond", - Usage: "Check if we can reduce the megapool bond", - UsageText: "rocketpool api megapool can-reduce-bond amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get amount - amount, err := cliutils.ValidatePositiveWeiAmount("amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canReduceBond(c, amount)) - return nil - - }, - }, - { - Name: "reduce-bond", - Aliases: []string{"rb"}, - Usage: "Reduce the megapool bond", - UsageText: "rocketpool api megapool reduce-bond amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get amount - amount, err := cliutils.ValidatePositiveWeiAmount("amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(reduceBond(c, amount)) - return nil - - }, - }, - { - Name: "can-claim-refund", - Usage: "Check if we can claim a megapool refund", - UsageText: "rocketpool api megapool can-claim-refund", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canClaimRefund(c)) - return nil - - }, - }, - { - Name: "claim-refund", - Aliases: []string{"cr"}, - Usage: "Claim a megapool refund", - UsageText: "rocketpool api megapool claim-refund", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(claimRefund(c)) - return nil - - }, - }, - { - Name: "can-stake", - Usage: "Check if we can stake a megapool validator", - UsageText: "rocketpool api megapool can-stake validator-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get the validatorId - validatorId, err := cliutils.ValidateUint("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canStake(c, validatorId)) - return nil - - }, - }, - { - Name: "stake", - Aliases: []string{"st"}, - Usage: "Stake a megapool validator", - UsageText: "rocketpool api megapool stake validator-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get validatorId - validatorId, err := cliutils.ValidateUint("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(stake(c, validatorId)) - return nil - - }, - }, - { - Name: "can-exit-queue", - Usage: "Check whether the node can exit the megapool queue", - UsageText: "rocketpool api megapool can-exit-queue validator-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Check the validator-id - validatorId, err := cliutils.ValidateUint32("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canExitQueue(c, validatorId)) - return nil - - }, - }, - { - Name: "exit-queue", - Usage: "Exit the megapool queue", - UsageText: "rocketpool api megapool exit-queue validator-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Check the validatorId - validatorId, err := cliutils.ValidateUint32("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(exitQueue(c, validatorId)) - return nil - - }, - }, - { - Name: "can-dissolve-validator", - Usage: "Check if we can dissolve a megapool validator", - UsageText: "rocketpool api megapool can-dissolve-validator validator-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get the validatorId - validatorId, err := cliutils.ValidateUint32("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canDissolveValidator(c, validatorId)) - return nil - - }, - }, - { - Name: "dissolve-validator", - Aliases: []string{"dv"}, - Usage: "Dissolve a megapool validator", - UsageText: "rocketpool api megapool dissolve-validator validator-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get validatorId - validatorId, err := cliutils.ValidateUint32("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(dissolveValidator(c, validatorId)) - return nil - - }, - }, - { - Name: "can-exit-validator", - Usage: "Check if we can exit a megapool validator", - UsageText: "rocketpool api megapool can-exit-validator validator-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get the validatorId - validatorId, err := cliutils.ValidateUint32("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canExitValidator(c, validatorId)) - return nil - - }, - }, - { - Name: "exit-validator", - Aliases: []string{"ev"}, - Usage: "Exit a megapool validator", - UsageText: "rocketpool api megapool exit-validator validator-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get validatorId - validatorId, err := cliutils.ValidateUint32("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(exitValidator(c, validatorId)) - return nil - - }, - }, - { - Name: "can-notify-validator-exit", - Usage: "Check if we can notify the exit of a megapool validator", - UsageText: "rocketpool api megapool can-notify-validator-exit validator-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get the validatorId - validatorId, err := cliutils.ValidateUint32("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canNotifyValidatorExit(c, validatorId)) - return nil - - }, - }, - { - Name: "notify-validator-exit", - Aliases: []string{"ev"}, - Usage: "Notify a megapool validator exit", - UsageText: "rocketpool api megapool notify-validator-exit validator-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Get validatorId - validatorId, err := cliutils.ValidateUint32("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(notifyValidatorExit(c, validatorId)) - return nil - - }, - }, - { - Name: "can-notify-final-balance", - Usage: "Check if we can notify the final balance of a megapool validator", - UsageText: "rocketpool api megapool can-notify-final-balance validator-id slot", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - - // Get the validatorId - validatorId, err := cliutils.ValidateUint32("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Get slot - slot, err := cliutils.ValidateUint("slot", c.Args().Get(1)) - if err != nil { - return err - } - // Run - api.PrintResponse(canNotifyFinalBalance(c, validatorId, slot)) - return nil - - }, - }, - { - Name: "notify-final-balance", - Aliases: []string{"ev"}, - Usage: "Notify a megapool validator final balance", - UsageText: "rocketpool api megapool notify-final-balance validator-id slot", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - - // Get validatorId - validatorId, err := cliutils.ValidateUint32("validatorId", c.Args().Get(0)) - if err != nil { - return err - } - - // Get slot - slot, err := cliutils.ValidateUint("slot", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(notifyFinalBalance(c, validatorId, slot)) - return nil - - }, - }, - { - Name: "get-use-latest-delegate", - Usage: "Gets the current setting of the 'always use latest delegate' toggle", - UsageText: "rocketpool api megapool get-use-latest-delegate megapool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - megapoolAddress, err := cliutils.ValidateAddress("megapool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getUseLatestDelegate(c, megapoolAddress)) - return nil - - }, - }, - { - Name: "can-set-use-latest-delegate", - Usage: "Check whether the 'always use latest delegate' toggle can be set", - UsageText: "rocketpool api megapool can-set-use-latest-delegate megapool-address use-latest-delegate", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - megapoolAddress, err := cliutils.ValidateAddress("megapool address", c.Args().Get(0)) - if err != nil { - return err - } - - useLatest, err := cliutils.ValidateBool("use-latest-delegate", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canSetUseLatestDelegate(c, megapoolAddress, useLatest)) - return nil - - }, - }, - { - Name: "set-use-latest-delegate", - Usage: "Set to ignore the megapool's current delegate, and always use the latest delegate instead", - UsageText: "rocketpool api megapool set-use-latest-delegate use-latest-delegate", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - megapoolAddress, err := cliutils.ValidateAddress("megapool address", c.Args().Get(0)) - if err != nil { - return err - } - - useLatest, err := cliutils.ValidateBool("use-latest-delegate", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(setUseLatestDelegate(c, megapoolAddress, useLatest)) - return nil - - }, - }, - { - Name: "get-delegate", - Usage: "Gets the address of the current delegate contract used by the megapool", - UsageText: "rocketpool api megapool get-delegate megapool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - megapoolAddress, err := cliutils.ValidateAddress("megapool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getDelegate(c, megapoolAddress)) - return nil - - }, - }, - { - Name: "get-effective-delegate", - Usage: "Gets the address of the effective delegate contract used by the megapool, which takes the UseLatestDelegate setting into account", - UsageText: "rocketpool api megapool get-effective-delegate megapool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - megapoolAddress, err := cliutils.ValidateAddress("megapool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getEffectiveDelegate(c, megapoolAddress)) - return nil - - }, - }, - { - Name: "can-delegate-upgrade", - Usage: "Check whether the megapool delegate can be upgraded", - UsageText: "rocketpool api megapool can-delegate-upgrade megapool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - megapoolAddress, err := cliutils.ValidateAddress("megapool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canDelegateUpgrade(c, megapoolAddress)) - return nil - - }, - }, - { - Name: "delegate-upgrade", - Usage: "Upgrade this megapool to the latest network delegate contract", - UsageText: "rocketpool api megapool delegate-upgrade megapool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - megapoolAddress, err := cliutils.ValidateAddress("megapool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(delegateUpgrade(c, megapoolAddress)) - return nil - - }, - }, - { - Name: "calculate-rewards", - Usage: "Calculate the rewards split given an eth amount", - UsageText: "rocketpool api megapool calculate-rewards amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - // Get amount - amount, err := cliutils.ValidatePositiveWeiAmount("amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(calculateRewards(c, amount)) - return nil - - }, - }, - { - Name: "pending-rewards", - Usage: "Calculate the pending rewards split", - UsageText: "rocketpool api megapool pending-rewards", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - // Run - api.PrintResponse(calculatePendingRewards(c)) - return nil - - }, - }, - { - Name: "get-new-validator-bond-requirement", - Usage: "Get the bond amount required for the megapool's next validator", - UsageText: "rocketpool api megapool get-new-validator-bond-requirement", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - // Run - api.PrintResponse(getNewValidatorBondRequirement(c)) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/megapool/delegate.go b/rocketpool/api/megapool/delegate.go index 756dd3e54..19bcc04f6 100644 --- a/rocketpool/api/megapool/delegate.go +++ b/rocketpool/api/megapool/delegate.go @@ -3,11 +3,11 @@ package megapool import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -49,16 +49,12 @@ func canDelegateUpgrade(c *cli.Command, megapoolAddress common.Address) (*api.Me return &response, nil } -func delegateUpgrade(c *cli.Command, megapoolAddress common.Address) (*api.MegapoolDelegateUpgradeResponse, error) { +func delegateUpgrade(c *cli.Command, megapoolAddress common.Address, opts *bind.TransactOpts) (*api.MegapoolDelegateUpgradeResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -73,18 +69,6 @@ func delegateUpgrade(c *cli.Command, megapoolAddress common.Address) (*api.Megap return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Upgrade hash, err := mega.DelegateUpgrade(opts) if err != nil { @@ -128,7 +112,7 @@ func getUseLatestDelegate(c *cli.Command, megapoolAddress common.Address) (*api. } -func canSetUseLatestDelegate(c *cli.Command, megapoolAddress common.Address, setting bool) (*api.MegapoolCanSetUseLatestDelegateResponse, error) { +func canSetUseLatestDelegate(c *cli.Command, megapoolAddress common.Address, useLatest bool) (*api.MegapoolCanSetUseLatestDelegateResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err @@ -156,7 +140,7 @@ func canSetUseLatestDelegate(c *cli.Command, megapoolAddress common.Address, set if err != nil { return nil, err } - if currentSetting == setting { + if currentSetting == useLatest { response.MatchesCurrentSetting = true return &response, nil } @@ -168,7 +152,7 @@ func canSetUseLatestDelegate(c *cli.Command, megapoolAddress common.Address, set return nil, err } - gasInfo, err := mega.EstimateSetUseLatestDelegateGas(setting, opts) + gasInfo, err := mega.EstimateSetUseLatestDelegateGas(useLatest, opts) if err == nil { response.GasInfo = gasInfo } @@ -178,15 +162,11 @@ func canSetUseLatestDelegate(c *cli.Command, megapoolAddress common.Address, set } -func setUseLatestDelegate(c *cli.Command, megapoolAddress common.Address, setting bool) (*api.MegapoolSetUseLatestDelegateResponse, error) { +func setUseLatestDelegate(c *cli.Command, megapoolAddress common.Address, useLatest bool, opts *bind.TransactOpts) (*api.MegapoolSetUseLatestDelegateResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -201,20 +181,8 @@ func setUseLatestDelegate(c *cli.Command, megapoolAddress common.Address, settin return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Set the new setting - hash, err := mega.SetUseLatestDelegate(setting, opts) + hash, err := mega.SetUseLatestDelegate(useLatest, opts) if err != nil { return nil, err } diff --git a/rocketpool/api/megapool/dissolve-validator.go b/rocketpool/api/megapool/dissolve-validator.go index 1384c45aa..de6d40e8b 100644 --- a/rocketpool/api/megapool/dissolve-validator.go +++ b/rocketpool/api/megapool/dissolve-validator.go @@ -1,12 +1,10 @@ package megapool import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -83,7 +81,7 @@ func canDissolveValidator(c *cli.Command, validatorId uint32) (*api.CanDissolveV } -func dissolveValidator(c *cli.Command, validatorId uint32) (*api.DissolveValidatorResponse, error) { +func dissolveValidator(c *cli.Command, validatorId uint32, opts *bind.TransactOpts) (*api.DissolveValidatorResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -119,18 +117,6 @@ func dissolveValidator(c *cli.Command, validatorId uint32) (*api.DissolveValidat return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Dissolve hash, err := mp.DissolveValidator(validatorId, opts) if err != nil { diff --git a/rocketpool/api/megapool/dissolve-with-proof.go b/rocketpool/api/megapool/dissolve-with-proof.go index 4e820a472..34f360f42 100644 --- a/rocketpool/api/megapool/dissolve-with-proof.go +++ b/rocketpool/api/megapool/dissolve-with-proof.go @@ -3,12 +3,12 @@ package megapool import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/rocket-pool/smartnode/bindings/types" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -110,7 +110,7 @@ func canDissolveWithProof(c *cli.Command, validatorId uint32) (*api.CanDissolveW } -func dissolveWithProof(c *cli.Command, validatorId uint32) (*api.DissolveWithProofResponse, error) { +func dissolveWithProof(c *cli.Command, validatorId uint32, opts *bind.TransactOpts) (*api.DissolveWithProofResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -165,18 +165,6 @@ func dissolveWithProof(c *cli.Command, validatorId uint32) (*api.DissolveWithPro return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Dissolve tx, err := megapool.DissolveWithProof(rp, megapoolAddress, validatorId, slotTimestamp, validatorProof, slotProof, opts) if err != nil { diff --git a/rocketpool/api/megapool/distribute.go b/rocketpool/api/megapool/distribute.go index dee731e54..f2de45f57 100644 --- a/rocketpool/api/megapool/distribute.go +++ b/rocketpool/api/megapool/distribute.go @@ -1,12 +1,10 @@ package megapool import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -93,7 +91,7 @@ func canDistributeMegapool(c *cli.Command) (*api.CanDistributeMegapoolResponse, return &response, nil } -func distributeMegapool(c *cli.Command) (*api.DistributeMegapoolResponse, error) { +func distributeMegapool(c *cli.Command, opts *bind.TransactOpts) (*api.DistributeMegapoolResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err @@ -115,18 +113,6 @@ func distributeMegapool(c *cli.Command) (*api.DistributeMegapoolResponse, error) return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Response response := api.DistributeMegapoolResponse{} diff --git a/rocketpool/api/megapool/exit-queue.go b/rocketpool/api/megapool/exit-queue.go index 5b9da30ea..e69ce609b 100644 --- a/rocketpool/api/megapool/exit-queue.go +++ b/rocketpool/api/megapool/exit-queue.go @@ -1,12 +1,10 @@ package megapool import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -76,7 +74,7 @@ func canExitQueue(c *cli.Command, validatorIndex uint32) (*api.CanExitQueueRespo } -func exitQueue(c *cli.Command, validatorIndex uint32) (*api.ExitQueueResponse, error) { +func exitQueue(c *cli.Command, validatorIndex uint32, opts *bind.TransactOpts) (*api.ExitQueueResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -102,18 +100,6 @@ func exitQueue(c *cli.Command, validatorIndex uint32) (*api.ExitQueueResponse, e // Response response := api.ExitQueueResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Get the megapool address megapoolAddress, err := megapool.GetMegapoolExpectedAddress(rp, nodeAccount.Address, nil) if err != nil { diff --git a/rocketpool/api/megapool/notify-final-balance.go b/rocketpool/api/megapool/notify-final-balance.go index 993bed565..dc1cbacb9 100644 --- a/rocketpool/api/megapool/notify-final-balance.go +++ b/rocketpool/api/megapool/notify-final-balance.go @@ -4,12 +4,12 @@ import ( "fmt" "strconv" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/rocket-pool/smartnode/bindings/types" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" cfgtypes "github.com/rocket-pool/smartnode/shared/types/config" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -138,7 +138,7 @@ func canNotifyFinalBalance(c *cli.Command, validatorId uint32, withdrawalSlot ui } -func notifyFinalBalance(c *cli.Command, validatorId uint32, withdrawalSlot uint64) (*api.NotifyValidatorExitResponse, error) { +func notifyFinalBalance(c *cli.Command, validatorId uint32, withdrawalSlot uint64, opts *bind.TransactOpts) (*api.NotifyValidatorExitResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -195,12 +195,6 @@ func notifyFinalBalance(c *cli.Command, validatorId uint32, withdrawalSlot uint6 return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - validatorStatus, err := bc.GetValidatorStatus(types.ValidatorPubkey(validatorInfo.Pubkey), nil) if err != nil { return nil, fmt.Errorf("Error getting validator status from beacon chain: %w", err) @@ -255,12 +249,6 @@ func notifyFinalBalance(c *cli.Command, validatorId uint32, withdrawalSlot uint6 return nil, err } - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Notify the validator exit tx, err := megapool.NotifyFinalBalance(rp, megapoolAddress, validatorId, slotTimestamp, finalBalanceProof, validatorProof, slotProof, opts) if err != nil { diff --git a/rocketpool/api/megapool/notify-validator-exit.go b/rocketpool/api/megapool/notify-validator-exit.go index 77587104a..064bb3189 100644 --- a/rocketpool/api/megapool/notify-validator-exit.go +++ b/rocketpool/api/megapool/notify-validator-exit.go @@ -1,13 +1,11 @@ package megapool import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/rocket-pool/smartnode/bindings/types" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -89,7 +87,7 @@ func canNotifyValidatorExit(c *cli.Command, validatorId uint32) (*api.CanNotifyV } -func notifyValidatorExit(c *cli.Command, validatorId uint32) (*api.NotifyValidatorExitResponse, error) { +func notifyValidatorExit(c *cli.Command, validatorId uint32, opts *bind.TransactOpts) (*api.NotifyValidatorExitResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -148,18 +146,6 @@ func notifyValidatorExit(c *cli.Command, validatorId uint32) (*api.NotifyValidat return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Notify the validator exit tx, err := megapool.NotifyExit(rp, megapoolAddress, validatorId, slotTimetamp, validatorProof, slotProof, opts) if err != nil { diff --git a/rocketpool/api/megapool/reduce-bond.go b/rocketpool/api/megapool/reduce-bond.go index b5052056d..745b0ea4b 100644 --- a/rocketpool/api/megapool/reduce-bond.go +++ b/rocketpool/api/megapool/reduce-bond.go @@ -1,15 +1,14 @@ package megapool import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canReduceBond(c *cli.Command, amount *big.Int) (*api.CanReduceBondResponse, error) { @@ -90,7 +89,7 @@ func canReduceBond(c *cli.Command, amount *big.Int) (*api.CanReduceBondResponse, } -func reduceBond(c *cli.Command, amount *big.Int) (*api.ReduceBondResponse, error) { +func reduceBond(c *cli.Command, amount *big.Int, opts *bind.TransactOpts) (*api.ReduceBondResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -126,18 +125,6 @@ func reduceBond(c *cli.Command, amount *big.Int) (*api.ReduceBondResponse, error return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Reduce bond hash, err := mp.ReduceBond(amount, opts) if err != nil { diff --git a/rocketpool/api/megapool/repay-debt.go b/rocketpool/api/megapool/repay-debt.go index fe8487794..259880aae 100644 --- a/rocketpool/api/megapool/repay-debt.go +++ b/rocketpool/api/megapool/repay-debt.go @@ -5,12 +5,12 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canRepayDebt(c *cli.Command, amount *big.Int) (*api.CanRepayDebtResponse, error) { @@ -103,7 +103,7 @@ func canRepayDebt(c *cli.Command, amount *big.Int) (*api.CanRepayDebtResponse, e } -func repayDebt(c *cli.Command, amount *big.Int) (*api.RepayDebtResponse, error) { +func repayDebt(c *cli.Command, amount *big.Int, opts *bind.TransactOpts) (*api.RepayDebtResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -149,20 +149,8 @@ func repayDebt(c *cli.Command, amount *big.Int) (*api.RepayDebtResponse, error) return nil, fmt.Errorf("no debt to repay") } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - opts.Value = amount - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Repay debt hash, err := mp.RepayDebt(opts) if err != nil { diff --git a/rocketpool/api/megapool/routes.go b/rocketpool/api/megapool/routes.go new file mode 100644 index 000000000..679370a60 --- /dev/null +++ b/rocketpool/api/megapool/routes.go @@ -0,0 +1,391 @@ +package megapool + +import ( + "fmt" + "math/big" + "net/http" + "strconv" + + "github.com/ethereum/go-ethereum/common" + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/shared/services" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +// RegisterRoutes registers the megapool module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/megapool/status", func(w http.ResponseWriter, r *http.Request) { + finalizedState := r.URL.Query().Get("finalizedState") == "true" + resp, err := getStatus(c, finalizedState) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/validator-map-and-balances", func(w http.ResponseWriter, r *http.Request) { + resp, err := getValidatorMapAndBalances(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-claim-refund", func(w http.ResponseWriter, r *http.Request) { + resp, err := canClaimRefund(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/claim-refund", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := claimRefund(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-repay-debt", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canRepayDebt(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/repay-debt", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := repayDebt(c, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-reduce-bond", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canReduceBond(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/reduce-bond", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := reduceBond(c, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-stake", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint64(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canStake(c, validatorId) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/stake", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint64(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := stake(c, validatorId, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-dissolve-validator", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint32(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canDissolveValidator(c, validatorId) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/dissolve-validator", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint32(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := dissolveValidator(c, validatorId, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-dissolve-with-proof", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint32(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canDissolveWithProof(c, validatorId) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/dissolve-with-proof", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint32(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := dissolveWithProof(c, validatorId, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-exit-validator", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint32(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canExitValidator(c, validatorId) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/exit-validator", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint32(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := exitValidator(c, validatorId) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-notify-validator-exit", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint32(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canNotifyValidatorExit(c, validatorId) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/notify-validator-exit", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint32(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := notifyValidatorExit(c, validatorId, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-notify-final-balance", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint32(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + slot, err := parseUint64(r, "slot") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canNotifyFinalBalance(c, validatorId, slot) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/notify-final-balance", func(w http.ResponseWriter, r *http.Request) { + validatorId, err := parseUint32(r, "validatorId") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + slot, err := parseUint64(r, "slot") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := notifyFinalBalance(c, validatorId, slot, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-exit-queue", func(w http.ResponseWriter, r *http.Request) { + validatorIndex, err := parseUint32(r, "validatorIndex") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canExitQueue(c, validatorIndex) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/exit-queue", func(w http.ResponseWriter, r *http.Request) { + validatorIndex, err := parseUint32(r, "validatorIndex") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := exitQueue(c, validatorIndex, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-distribute", func(w http.ResponseWriter, r *http.Request) { + resp, err := canDistributeMegapool(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/distribute", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := distributeMegapool(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/get-new-validator-bond-requirement", func(w http.ResponseWriter, r *http.Request) { + resp, err := getNewValidatorBondRequirement(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/pending-rewards", func(w http.ResponseWriter, r *http.Request) { + resp, err := calculatePendingRewards(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/calculate-rewards", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := calculateRewards(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/get-use-latest-delegate", func(w http.ResponseWriter, r *http.Request) { + address := common.HexToAddress(r.URL.Query().Get("address")) + resp, err := getUseLatestDelegate(c, address) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-delegate-upgrade", func(w http.ResponseWriter, r *http.Request) { + address := common.HexToAddress(r.URL.Query().Get("address")) + resp, err := canDelegateUpgrade(c, address) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/delegate-upgrade", func(w http.ResponseWriter, r *http.Request) { + address := common.HexToAddress(r.FormValue("address")) + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := delegateUpgrade(c, address, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/can-set-use-latest-delegate", func(w http.ResponseWriter, r *http.Request) { + address := common.HexToAddress(r.URL.Query().Get("address")) + setLatest := r.URL.Query().Get("setLatest") == "true" + resp, err := canSetUseLatestDelegate(c, address, setLatest) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/set-use-latest-delegate", func(w http.ResponseWriter, r *http.Request) { + address := common.HexToAddress(r.FormValue("address")) + setting := r.FormValue("setting") == "true" + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setUseLatestDelegate(c, address, setting, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/get-delegate", func(w http.ResponseWriter, r *http.Request) { + address := common.HexToAddress(r.URL.Query().Get("address")) + resp, err := getDelegate(c, address) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/megapool/get-effective-delegate", func(w http.ResponseWriter, r *http.Request) { + address := common.HexToAddress(r.URL.Query().Get("address")) + resp, err := getEffectiveDelegate(c, address) + apiutils.WriteResponse(w, resp, err) + }) +} + +func parseUint64(r *http.Request, name string) (uint64, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + return strconv.ParseUint(raw, 10, 64) +} + +func parseUint32(r *http.Request, name string) (uint32, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + v, err := strconv.ParseUint(raw, 10, 32) + return uint32(v), err +} + +func parseBigInt(r *http.Request, name string) (*big.Int, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + v, ok := new(big.Int).SetString(raw, 10) + if !ok { + return nil, fmt.Errorf("invalid %s: %s", name, raw) + } + return v, nil +} diff --git a/rocketpool/api/megapool/stake.go b/rocketpool/api/megapool/stake.go index c5a02ee31..290d0f237 100644 --- a/rocketpool/api/megapool/stake.go +++ b/rocketpool/api/megapool/stake.go @@ -1,16 +1,15 @@ package megapool import ( - "fmt" "strings" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/rocket-pool/smartnode/bindings/types" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canStake(c *cli.Command, validatorId uint64) (*api.CanStakeResponse, error) { @@ -115,7 +114,7 @@ func canStake(c *cli.Command, validatorId uint64) (*api.CanStakeResponse, error) } -func stake(c *cli.Command, validatorId uint64) (*api.StakeResponse, error) { +func stake(c *cli.Command, validatorId uint64, opts *bind.TransactOpts) (*api.StakeResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -170,18 +169,6 @@ func stake(c *cli.Command, validatorId uint64) (*api.StakeResponse, error) { return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Stake tx, err := megapool.Stake(rp, megapoolAddress, uint32(validatorId), slotTimestamp, validatorProof, slotProof, opts) if err != nil { diff --git a/rocketpool/api/minipool/close.go b/rocketpool/api/minipool/close.go index 43e4d6e3e..70f8e23cb 100644 --- a/rocketpool/api/minipool/close.go +++ b/rocketpool/api/minipool/close.go @@ -18,7 +18,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/services/beacon" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func getMinipoolCloseDetailsForNode(c *cli.Command) (*api.GetMinipoolCloseDetailsForNodeResponse, error) { @@ -307,16 +306,12 @@ func getMinipoolCloseDetails(rp *rocketpool.RocketPool, minipoolAddress common.A } -func closeMinipool(c *cli.Command, minipoolAddress common.Address) (*api.CloseMinipoolResponse, error) { +func closeMinipool(c *cli.Command, minipoolAddress common.Address, opts *bind.TransactOpts) (*api.CloseMinipoolResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -337,18 +332,6 @@ func closeMinipool(c *cli.Command, minipoolAddress common.Address) (*api.CloseMi return nil, fmt.Errorf("cannot create v3 binding for minipool %s, version %d", minipoolAddress.Hex(), mp.GetVersion()) } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Get some details var status types.MinipoolStatus var distributed bool diff --git a/rocketpool/api/minipool/commands.go b/rocketpool/api/minipool/commands.go deleted file mode 100644 index e133bacc9..000000000 --- a/rocketpool/api/minipool/commands.go +++ /dev/null @@ -1,596 +0,0 @@ -package minipool - -import ( - "context" - - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage the node's minipools", - Commands: []*cli.Command{ - - { - Name: "status", - Aliases: []string{"s"}, - Usage: "Get a list of the node's minipools", - UsageText: "rocketpool api minipool status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getStatus(c)) - return nil - - }, - }, - - { - Name: "can-stake", - Usage: "Check whether the minipool is ready to be staked, moving from prelaunch to staking status", - UsageText: "rocketpool api minipool can-stake minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canStakeMinipool(c, minipoolAddress)) - return nil - - }, - }, - { - Name: "stake", - Aliases: []string{"t"}, - Usage: "Stake the minipool, moving it from prelaunch to staking status", - UsageText: "rocketpool api minipool stake minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(stakeMinipool(c, minipoolAddress)) - return nil - - }, - }, - - { - Name: "can-promote", - Usage: "Check whether a vacant minipool is ready to be promoted", - UsageText: "rocketpool api minipool can-promote minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canPromoteMinipool(c, minipoolAddress)) - return nil - - }, - }, - { - Name: "promote", - Usage: "Promote a vacant minipool", - UsageText: "rocketpool api minipool promote minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(promoteMinipool(c, minipoolAddress)) - return nil - - }, - }, - - { - Name: "can-refund", - Usage: "Check whether the node can refund ETH from the minipool", - UsageText: "rocketpool api minipool can-refund minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canRefundMinipool(c, minipoolAddress)) - return nil - - }, - }, - { - Name: "refund", - Aliases: []string{"r"}, - Usage: "Refund ETH belonging to the node from a minipool", - UsageText: "rocketpool api minipool refund minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(refundMinipool(c, minipoolAddress)) - return nil - - }, - }, - - { - Name: "can-dissolve", - Usage: "Check whether the minipool can be dissolved", - UsageText: "rocketpool api minipool can-dissolve minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canDissolveMinipool(c, minipoolAddress)) - return nil - - }, - }, - { - Name: "dissolve", - Aliases: []string{"d"}, - Usage: "Dissolve an initialized or prelaunch minipool", - UsageText: "rocketpool api minipool dissolve minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(dissolveMinipool(c, minipoolAddress)) - return nil - - }, - }, - - { - Name: "can-exit", - Usage: "Check whether the minipool can be exited from the beacon chain", - UsageText: "rocketpool api minipool can-exit minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canExitMinipool(c, minipoolAddress)) - return nil - - }, - }, - { - Name: "exit", - Aliases: []string{"e"}, - Usage: "Exit a staking minipool from the beacon chain", - UsageText: "rocketpool api minipool exit minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(exitMinipool(c, minipoolAddress)) - return nil - - }, - }, - - { - Name: "get-minipool-close-details-for-node", - Usage: "Check all of the node's minipools for closure eligibility, and return the details of the closeable ones", - UsageText: "rocketpool api minipool get-minipool-close-details-for-node", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getMinipoolCloseDetailsForNode(c)) - return nil - - }, - }, - { - Name: "close", - Aliases: []string{"c"}, - Usage: "Withdraw balance from a dissolved minipool and close it", - UsageText: "rocketpool api minipool close minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(closeMinipool(c, minipoolAddress)) - return nil - - }, - }, - - { - Name: "can-delegate-upgrade", - Usage: "Check whether the minipool delegate can be upgraded", - UsageText: "rocketpool api minipool can-delegate-upgrade minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canDelegateUpgrade(c, minipoolAddress)) - return nil - - }, - }, - { - Name: "delegate-upgrade", - Usage: "Upgrade this minipool to the latest network delegate contract", - UsageText: "rocketpool api minipool delegate-upgrade minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(delegateUpgrade(c, minipoolAddress)) - return nil - - }, - }, - - { - Name: "get-use-latest-delegate", - Usage: "Gets the current setting of the 'always use latest delegate' toggle", - UsageText: "rocketpool api minipool get-use-latest-delegate minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getUseLatestDelegate(c, minipoolAddress)) - return nil - - }, - }, - - { - Name: "get-delegate", - Usage: "Gets the address of the current delegate contract used by the minipool", - UsageText: "rocketpool api minipool get-delegate minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getDelegate(c, minipoolAddress)) - return nil - - }, - }, - - { - Name: "get-effective-delegate", - Usage: "Gets the address of the effective delegate contract used by the minipool, which takes the UseLatestDelegate setting into account", - UsageText: "rocketpool api minipool get-effective-delegate minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getEffectiveDelegate(c, minipoolAddress)) - return nil - - }, - }, - - { - Name: "get-vanity-artifacts", - Aliases: []string{"v"}, - Usage: "Gets the data necessary to search for vanity minipool addresses", - UsageText: "rocketpool api minipool get-vanity-artifacts deposit node-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - depositAmount, err := cliutils.ValidatePositiveWeiAmount("deposit amount", c.Args().Get(0)) - if err != nil { - return err - } - nodeAddressStr := c.Args().Get(1) - - // Run - api.PrintResponse(getVanityArtifacts(c, depositAmount, nodeAddressStr)) - return nil - - }, - }, - - { - Name: "get-distribute-balance-details", - Usage: "Get the balance distribution details for all of the node's minipools", - UsageText: "rocketpool api minipool get-distribute-balance-details", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getDistributeBalanceDetails(c)) - return nil - - }, - }, - { - Name: "distribute-balance", - Usage: "Distribute a minipool's ETH balance", - UsageText: "rocketpool api minipool distribute-balance minipool-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(distributeBalance(c, minipoolAddress)) - return nil - - }, - }, - - { - Name: "import-key", - Usage: "Import a validator private key for a vacant minipool", - UsageText: "rocketpool api minipool import-key minipool-address mnemonic", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - mnemonic, err := cliutils.ValidateWalletMnemonic("mnemonic", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(importKey(c, minipoolAddress, mnemonic)) - return nil - - }, - }, - - { - Name: "can-change-withdrawal-creds", - Usage: "Check whether a solo validator's withdrawal credentials can be changed to a minipool address", - UsageText: "rocketpool api minipool can-change-withdrawal-creds minipool-address mnemonic", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - mnemonic, err := cliutils.ValidateWalletMnemonic("mnemonic", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canChangeWithdrawalCreds(c, minipoolAddress, mnemonic)) - return nil - - }, - }, - { - Name: "change-withdrawal-creds", - Usage: "Change a solo validator's withdrawal credentials to a minipool address", - UsageText: "rocketpool api minipool change-withdrawal-creds minipool-address mnemonic", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - mnemonic, err := cliutils.ValidateWalletMnemonic("mnemonic", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(changeWithdrawalCreds(c, minipoolAddress, mnemonic)) - return nil - - }, - }, - - { - Name: "get-rescue-dissolved-details-for-node", - Usage: "Check all of the node's minipools for rescue eligibility, and return the details of the rescuable ones", - UsageText: "rocketpool api minipool get-rescue-dissolved-details-for-node", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getMinipoolRescueDissolvedDetailsForNode(c)) - return nil - - }, - }, - - { - Name: "rescue-dissolved", - Usage: "Rescue a dissolved minipool by depositing ETH for it to the Beacon deposit contract", - UsageText: "rocketpool api minipool rescue-dissolved minipool-address deposit-amount submit", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - minipoolAddress, err := cliutils.ValidateAddress("minipool address", c.Args().Get(0)) - if err != nil { - return err - } - depositAmount, err := cliutils.ValidateBigInt("deposit amount", c.Args().Get(1)) - if err != nil { - return err - } - submit, err := cliutils.ValidateBool("submit", c.Args().Get(2)) - if err != nil { - return err - } - - // Run - api.PrintResponse(rescueDissolvedMinipool(c, minipoolAddress, depositAmount, submit)) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/minipool/delegate.go b/rocketpool/api/minipool/delegate.go index 3c0850e22..39461ad3e 100644 --- a/rocketpool/api/minipool/delegate.go +++ b/rocketpool/api/minipool/delegate.go @@ -3,6 +3,7 @@ package minipool import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/minipool" "github.com/rocket-pool/smartnode/bindings/rocketpool" @@ -11,7 +12,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canDelegateUpgrade(c *cli.Command, minipoolAddress common.Address) (*api.CanDelegateUpgradeResponse, error) { @@ -60,16 +60,12 @@ func canDelegateUpgrade(c *cli.Command, minipoolAddress common.Address) (*api.Ca } -func delegateUpgrade(c *cli.Command, minipoolAddress common.Address) (*api.DelegateUpgradeResponse, error) { +func delegateUpgrade(c *cli.Command, minipoolAddress common.Address, opts *bind.TransactOpts) (*api.DelegateUpgradeResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -84,18 +80,6 @@ func delegateUpgrade(c *cli.Command, minipoolAddress common.Address) (*api.Deleg return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Upgrade hash, err := mp.DelegateUpgrade(opts) if err != nil { @@ -174,17 +158,13 @@ func canSetUseLatestDelegate(c *cli.Command, minipoolAddress common.Address) (*a } -func setUseLatestDelegate(c *cli.Command, minipoolAddress common.Address) (*api.SetUseLatestDelegateResponse, error) { +func setUseLatestDelegate(c *cli.Command, minipoolAddress common.Address, opts *bind.TransactOpts) (*api.SetUseLatestDelegateResponse, error) { setting := true // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -225,18 +205,6 @@ func setUseLatestDelegate(c *cli.Command, minipoolAddress common.Address) (*api. } } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Set the new setting hash, err := mp.SetUseLatestDelegate(opts) if err != nil { diff --git a/rocketpool/api/minipool/dissolve.go b/rocketpool/api/minipool/dissolve.go index 8c2a6daf1..95fec9633 100644 --- a/rocketpool/api/minipool/dissolve.go +++ b/rocketpool/api/minipool/dissolve.go @@ -1,8 +1,7 @@ package minipool import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/minipool" "github.com/rocket-pool/smartnode/bindings/types" @@ -10,7 +9,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canDissolveMinipool(c *cli.Command, minipoolAddress common.Address) (*api.CanDissolveMinipoolResponse, error) { @@ -69,16 +67,12 @@ func canDissolveMinipool(c *cli.Command, minipoolAddress common.Address) (*api.C } -func dissolveMinipool(c *cli.Command, minipoolAddress common.Address) (*api.DissolveMinipoolResponse, error) { +func dissolveMinipool(c *cli.Command, minipoolAddress common.Address, opts *bind.TransactOpts) (*api.DissolveMinipoolResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -93,18 +87,6 @@ func dissolveMinipool(c *cli.Command, minipoolAddress common.Address) (*api.Diss return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Dissolve hash, err := mp.Dissolve(opts) if err != nil { diff --git a/rocketpool/api/minipool/distribute.go b/rocketpool/api/minipool/distribute.go index d6d8f9be7..3ea08a3e1 100644 --- a/rocketpool/api/minipool/distribute.go +++ b/rocketpool/api/minipool/distribute.go @@ -5,6 +5,7 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/minipool" "github.com/rocket-pool/smartnode/bindings/types" @@ -14,7 +15,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func getDistributeBalanceDetails(c *cli.Command) (*api.GetDistributeBalanceDetailsResponse, error) { @@ -191,16 +191,12 @@ func getDistributeBalanceDetails(c *cli.Command) (*api.GetDistributeBalanceDetai } -func distributeBalance(c *cli.Command, minipoolAddress common.Address) (*api.CloseMinipoolResponse, error) { +func distributeBalance(c *cli.Command, minipoolAddress common.Address, opts *bind.TransactOpts) (*api.CloseMinipoolResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -215,18 +211,6 @@ func distributeBalance(c *cli.Command, minipoolAddress common.Address) (*api.Clo return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Distribute the minipool's balance mpv3, success := minipool.GetMinipoolAsV3(mp) if !success { diff --git a/rocketpool/api/minipool/promote.go b/rocketpool/api/minipool/promote.go index 76b370f27..c9299f991 100644 --- a/rocketpool/api/minipool/promote.go +++ b/rocketpool/api/minipool/promote.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/minipool" "github.com/rocket-pool/smartnode/bindings/settings/trustednode" @@ -12,7 +13,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canPromoteMinipool(c *cli.Command, minipoolAddress common.Address) (*api.CanPromoteMinipoolResponse, error) { @@ -111,16 +111,12 @@ func canPromoteMinipool(c *cli.Command, minipoolAddress common.Address) (*api.Ca } -func promoteMinipool(c *cli.Command, minipoolAddress common.Address) (*api.StakeMinipoolResponse, error) { +func promoteMinipool(c *cli.Command, minipoolAddress common.Address, opts *bind.TransactOpts) (*api.StakeMinipoolResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -139,18 +135,6 @@ func promoteMinipool(c *cli.Command, minipoolAddress common.Address) (*api.Stake return nil, fmt.Errorf("cannot promte minipool %s because its delegate version is too low (v%d); please update the delegate to promote it", mp.GetAddress().Hex(), mp.GetVersion()) } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Promote hash, err := mpv3.Promote(opts) if err != nil { diff --git a/rocketpool/api/minipool/refund.go b/rocketpool/api/minipool/refund.go index ac9ec36ea..78f7ce15b 100644 --- a/rocketpool/api/minipool/refund.go +++ b/rocketpool/api/minipool/refund.go @@ -1,16 +1,15 @@ package minipool import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/minipool" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canRefundMinipool(c *cli.Command, minipoolAddress common.Address) (*api.CanRefundMinipoolResponse, error) { @@ -69,16 +68,12 @@ func canRefundMinipool(c *cli.Command, minipoolAddress common.Address) (*api.Can } -func refundMinipool(c *cli.Command, minipoolAddress common.Address) (*api.RefundMinipoolResponse, error) { +func refundMinipool(c *cli.Command, minipoolAddress common.Address, opts *bind.TransactOpts) (*api.RefundMinipoolResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -93,18 +88,6 @@ func refundMinipool(c *cli.Command, minipoolAddress common.Address) (*api.Refund return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Refund hash, err := mp.Refund(opts) if err != nil { diff --git a/rocketpool/api/minipool/rescue-dissolved.go b/rocketpool/api/minipool/rescue-dissolved.go index 5a3898ee0..99b527d75 100644 --- a/rocketpool/api/minipool/rescue-dissolved.go +++ b/rocketpool/api/minipool/rescue-dissolved.go @@ -19,7 +19,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services/contracts" "github.com/rocket-pool/smartnode/shared/services/wallet" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/rocket-pool/smartnode/shared/utils/validator" ) @@ -281,7 +280,7 @@ func getDepositTx(rp *rocketpool.RocketPool, w wallet.Wallet, bc beacon.Client, } -func rescueDissolvedMinipool(c *cli.Command, minipoolAddress common.Address, amount *big.Int, submit bool) (*api.RescueDissolvedMinipoolResponse, error) { +func rescueDissolvedMinipool(c *cli.Command, minipoolAddress common.Address, amount *big.Int, submit bool, opts *bind.TransactOpts) (*api.RescueDissolvedMinipoolResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -303,19 +302,8 @@ func rescueDissolvedMinipool(c *cli.Command, minipoolAddress common.Address, amo // Response response := api.RescueDissolvedMinipoolResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } opts.Value = amount - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - opts.NoSend = !submit // Submit the rescue deposit diff --git a/rocketpool/api/minipool/routes.go b/rocketpool/api/minipool/routes.go new file mode 100644 index 000000000..32eb2c058 --- /dev/null +++ b/rocketpool/api/minipool/routes.go @@ -0,0 +1,355 @@ +package minipool + +import ( + "fmt" + "math/big" + "net/http" + + "github.com/ethereum/go-ethereum/common" + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/shared/services" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +// RegisterRoutes registers the minipool module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/minipool/status", func(w http.ResponseWriter, r *http.Request) { + resp, err := getStatus(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/can-refund", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canRefundMinipool(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/refund", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := refundMinipool(c, addr, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/can-stake", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canStakeMinipool(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/stake", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := stakeMinipool(c, addr, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/can-promote", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canPromoteMinipool(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/promote", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := promoteMinipool(c, addr, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/can-dissolve", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canDissolveMinipool(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/dissolve", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := dissolveMinipool(c, addr, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/can-exit", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canExitMinipool(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/exit", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := exitMinipool(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/get-minipool-close-details-for-node", func(w http.ResponseWriter, r *http.Request) { + resp, err := getMinipoolCloseDetailsForNode(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/close", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := closeMinipool(c, addr, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/can-delegate-upgrade", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canDelegateUpgrade(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/delegate-upgrade", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := delegateUpgrade(c, addr, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/can-set-use-latest-delegate", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canSetUseLatestDelegate(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/set-use-latest-delegate", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setUseLatestDelegate(c, addr, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/get-use-latest-delegate", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := getUseLatestDelegate(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/get-delegate", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := getDelegate(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/get-effective-delegate", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := getEffectiveDelegate(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/get-previous-delegate", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := getPreviousDelegate(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/get-vanity-artifacts", func(w http.ResponseWriter, r *http.Request) { + depositAmountStr := r.URL.Query().Get("depositAmount") + depositAmount, ok := new(big.Int).SetString(depositAmountStr, 10) + if !ok { + apiutils.WriteErrorResponse(w, fmt.Errorf("invalid depositAmount: %s", depositAmountStr)) + return + } + nodeAddressStr := r.URL.Query().Get("nodeAddress") + resp, err := getVanityArtifacts(c, depositAmount, nodeAddressStr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/get-distribute-balance-details", func(w http.ResponseWriter, r *http.Request) { + resp, err := getDistributeBalanceDetails(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/distribute-balance", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := distributeBalance(c, addr, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/import-key", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + mnemonic := r.FormValue("mnemonic") + resp, err := importKey(c, addr, mnemonic) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/can-change-withdrawal-creds", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + mnemonic := r.URL.Query().Get("mnemonic") + resp, err := canChangeWithdrawalCreds(c, addr, mnemonic) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/change-withdrawal-creds", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + mnemonic := r.FormValue("mnemonic") + resp, err := changeWithdrawalCreds(c, addr, mnemonic) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/get-rescue-dissolved-details-for-node", func(w http.ResponseWriter, r *http.Request) { + resp, err := getMinipoolRescueDissolvedDetailsForNode(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/minipool/rescue-dissolved", func(w http.ResponseWriter, r *http.Request) { + addr, err := parseAddress(r, "address") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + amountStr := r.FormValue("amount") + amount, ok := new(big.Int).SetString(amountStr, 10) + if !ok { + apiutils.WriteErrorResponse(w, fmt.Errorf("invalid amount: %s", amountStr)) + return + } + submit := r.FormValue("submit") == "true" + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := rescueDissolvedMinipool(c, addr, amount, submit, opts) + apiutils.WriteResponse(w, resp, err) + }) + +} + +func parseAddress(r *http.Request, name string) (common.Address, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + if raw == "" { + return common.Address{}, fmt.Errorf("missing required parameter: %s", name) + } + return common.HexToAddress(raw), nil +} diff --git a/rocketpool/api/minipool/stake.go b/rocketpool/api/minipool/stake.go index ea2bd2320..72a2337a9 100644 --- a/rocketpool/api/minipool/stake.go +++ b/rocketpool/api/minipool/stake.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/minipool" "github.com/rocket-pool/smartnode/bindings/settings/trustednode" @@ -13,7 +14,6 @@ import ( rptypes "github.com/rocket-pool/smartnode/bindings/types" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/rocket-pool/smartnode/shared/utils/validator" ) @@ -149,7 +149,7 @@ func canStakeMinipool(c *cli.Command, minipoolAddress common.Address) (*api.CanS } -func stakeMinipool(c *cli.Command, minipoolAddress common.Address) (*api.StakeMinipoolResponse, error) { +func stakeMinipool(c *cli.Command, minipoolAddress common.Address, opts *bind.TransactOpts) (*api.StakeMinipoolResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -177,18 +177,6 @@ func stakeMinipool(c *cli.Command, minipoolAddress common.Address) (*api.StakeMi return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Get eth2 config eth2Config, err := bc.GetEth2Config() if err != nil { diff --git a/rocketpool/api/network/commands.go b/rocketpool/api/network/commands.go deleted file mode 100644 index e0857bf68..000000000 --- a/rocketpool/api/network/commands.go +++ /dev/null @@ -1,203 +0,0 @@ -package network - -import ( - "context" - - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage Rocket Pool network parameters", - Commands: []*cli.Command{ - - { - Name: "node-fee", - Aliases: []string{"f"}, - Usage: "Get the current network node commission rate", - UsageText: "rocketpool api network node-fee", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getNodeFee(c)) - return nil - - }, - }, - - { - Name: "rpl-price", - Aliases: []string{"p"}, - Usage: "Get the current network RPL price in ETH", - UsageText: "rocketpool api network rpl-price", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getRplPrice(c)) - return nil - - }, - }, - - { - Name: "stats", - Aliases: []string{"s"}, - Usage: "Get stats about the Rocket Pool network and its tokens", - UsageText: "rocketpool api network stats", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getStats(c)) - return nil - - }, - }, - - { - Name: "timezone-map", - Aliases: []string{"t"}, - Usage: "Get the table of node operators by timezone", - UsageText: "rocketpool api network stats", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getTimezones(c)) - return nil - - }, - }, - - { - Name: "can-generate-rewards-tree", - Usage: "Check if the rewards tree for the provided interval can be generated", - UsageText: "rocketpool api network can-generate-rewards-tree index", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - index, err := cliutils.ValidateUint("index", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canGenerateRewardsTree(c, index)) - return nil - - }, - }, - - { - Name: "generate-rewards-tree", - Usage: "Set a request marker for the watchtower to generate the rewards tree for the given interval", - UsageText: "rocketpool api network generate-rewards-tree index", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - index, err := cliutils.ValidateUint("index", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(generateRewardsTree(c, index)) - return nil - - }, - }, - - { - Name: "dao-proposals", - Aliases: []string{"d"}, - Usage: "Get the currently active DAO proposals", - UsageText: "rocketpool api network dao-proposals", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getActiveDAOProposals(c)) - return nil - - }, - }, - - { - Name: "download-rewards-file", - Aliases: []string{"drf"}, - Usage: "Download a rewards info file from IPFS for the given interval", - UsageText: "rocketpool api service download-rewards-file interval", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - interval, err := cliutils.ValidateUint("interval", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(downloadRewardsFile(c, interval)) - return nil - - }, - }, - { - Name: "latest-delegate", - Usage: "Get the address of the latest minipool delegate contract.", - UsageText: "rocketpool api network latest-delegate", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getLatestDelegate(c)) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/network/routes.go b/rocketpool/api/network/routes.go new file mode 100644 index 000000000..bc07a5b61 --- /dev/null +++ b/rocketpool/api/network/routes.go @@ -0,0 +1,81 @@ +package network + +import ( + "net/http" + "strconv" + + "github.com/urfave/cli/v3" + + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +// RegisterRoutes registers the network module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/network/node-fee", func(w http.ResponseWriter, r *http.Request) { + resp, err := getNodeFee(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/network/rpl-price", func(w http.ResponseWriter, r *http.Request) { + resp, err := getRplPrice(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/network/stats", func(w http.ResponseWriter, r *http.Request) { + resp, err := getStats(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/network/timezone-map", func(w http.ResponseWriter, r *http.Request) { + resp, err := getTimezones(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/network/can-generate-rewards-tree", func(w http.ResponseWriter, r *http.Request) { + index, err := parseUint64Param(r, "index") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canGenerateRewardsTree(c, index) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/network/generate-rewards-tree", func(w http.ResponseWriter, r *http.Request) { + index, err := parseUint64Param(r, "index") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := generateRewardsTree(c, index) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/network/dao-proposals", func(w http.ResponseWriter, r *http.Request) { + resp, err := getActiveDAOProposals(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/network/download-rewards-file", func(w http.ResponseWriter, r *http.Request) { + interval, err := parseUint64Param(r, "interval") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := downloadRewardsFile(c, interval) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/network/latest-delegate", func(w http.ResponseWriter, r *http.Request) { + resp, err := getLatestDelegate(c) + apiutils.WriteResponse(w, resp, err) + }) +} + +func parseUint64Param(r *http.Request, name string) (uint64, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + return strconv.ParseUint(raw, 10, 64) +} diff --git a/rocketpool/api/node/burn.go b/rocketpool/api/node/burn.go index d253597c4..ae75e0632 100644 --- a/rocketpool/api/node/burn.go +++ b/rocketpool/api/node/burn.go @@ -1,16 +1,16 @@ package node import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/rocket-pool/smartnode/bindings/tokens" "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canNodeBurn(c *cli.Command, amountWei *big.Int, token string) (*api.CanNodeBurnResponse, error) { @@ -103,7 +103,7 @@ func canNodeBurn(c *cli.Command, amountWei *big.Int, token string) (*api.CanNode } -func nodeBurn(c *cli.Command, amountWei *big.Int, token string) (*api.NodeBurnResponse, error) { +func nodeBurn(c *cli.Command, amountWei *big.Int, token string, opts *bind.TransactOpts) (*api.NodeBurnResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -112,10 +112,6 @@ func nodeBurn(c *cli.Command, amountWei *big.Int, token string) (*api.NodeBurnRe if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -124,18 +120,6 @@ func nodeBurn(c *cli.Command, amountWei *big.Int, token string) (*api.NodeBurnRe // Response response := api.NodeBurnResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Handle token type switch token { case "reth": diff --git a/rocketpool/api/node/claim-rewards.go b/rocketpool/api/node/claim-rewards.go index dd433e0cd..d6a62ca60 100644 --- a/rocketpool/api/node/claim-rewards.go +++ b/rocketpool/api/node/claim-rewards.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" @@ -21,7 +22,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services/config" rprewards "github.com/rocket-pool/smartnode/shared/services/rewards" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" rputils "github.com/rocket-pool/smartnode/shared/utils/rp" ) @@ -240,7 +240,7 @@ func canClaimRewards(c *cli.Command, indicesString string) (*api.CanNodeClaimRew return &response, nil } -func claimRewards(c *cli.Command, indicesString string) (*api.NodeClaimRewardsResponse, error) { +func claimRewards(c *cli.Command, indicesString string, opts *bind.TransactOpts) (*api.NodeClaimRewardsResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -268,18 +268,6 @@ func claimRewards(c *cli.Command, indicesString string) (*api.NodeClaimRewardsRe return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Get the rewards claims, err := getRewardsForIntervals(rp, cfg, nodeAccount.Address, indicesString) if err != nil { @@ -345,7 +333,7 @@ func canClaimAndStakeRewards(c *cli.Command, indicesString string, stakeAmount * } -func claimAndStakeRewards(c *cli.Command, indicesString string, stakeAmount *big.Int) (*api.NodeClaimAndStakeRewardsResponse, error) { +func claimAndStakeRewards(c *cli.Command, indicesString string, stakeAmount *big.Int, opts *bind.TransactOpts) (*api.NodeClaimAndStakeRewardsResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -373,18 +361,6 @@ func claimAndStakeRewards(c *cli.Command, indicesString string, stakeAmount *big return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Get the rewards claims, err := getRewardsForIntervals(rp, cfg, nodeAccount.Address, indicesString) if err != nil { diff --git a/rocketpool/api/node/claim-rpl.go b/rocketpool/api/node/claim-rpl.go index a67828ac5..f813be4d8 100644 --- a/rocketpool/api/node/claim-rpl.go +++ b/rocketpool/api/node/claim-rpl.go @@ -4,12 +4,13 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/bindings/legacy/v1.0.0/rewards" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canNodeClaimRpl(c *cli.Command) (*api.CanNodeClaimRplResponse, error) { @@ -75,7 +76,7 @@ func canNodeClaimRpl(c *cli.Command) (*api.CanNodeClaimRplResponse, error) { return &response, nil } -func nodeClaimRpl(c *cli.Command) (*api.NodeClaimRplResponse, error) { +func nodeClaimRpl(c *cli.Command, opts *bind.TransactOpts) (*api.NodeClaimRplResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -84,10 +85,6 @@ func nodeClaimRpl(c *cli.Command) (*api.NodeClaimRplResponse, error) { if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -100,18 +97,6 @@ func nodeClaimRpl(c *cli.Command) (*api.NodeClaimRplResponse, error) { // Response response := api.NodeClaimRplResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Claim rewards legacyClaimNodeAddress := cfg.Smartnode.GetV100ClaimNodeAddress() hash, err := rewards.ClaimNodeRewards(rp, opts, &legacyClaimNodeAddress) diff --git a/rocketpool/api/node/claim-unclaimed-rewards.go b/rocketpool/api/node/claim-unclaimed-rewards.go index 81bb93ff3..cfb3fcf17 100644 --- a/rocketpool/api/node/claim-unclaimed-rewards.go +++ b/rocketpool/api/node/claim-unclaimed-rewards.go @@ -1,15 +1,13 @@ package node import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canClaimUnclaimedRewards(c *cli.Command, nodeAddress common.Address) (*api.CanClaimUnclaimedRewardsResponse, error) { @@ -53,16 +51,12 @@ func canClaimUnclaimedRewards(c *cli.Command, nodeAddress common.Address) (*api. } -func claimUnclaimedRewards(c *cli.Command, nodeAddress common.Address) (*api.ClaimUnclaimedRewardsResponse, error) { +func claimUnclaimedRewards(c *cli.Command, nodeAddress common.Address, opts *bind.TransactOpts) (*api.ClaimUnclaimedRewardsResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -71,18 +65,6 @@ func claimUnclaimedRewards(c *cli.Command, nodeAddress common.Address) (*api.Cla // Response response := api.ClaimUnclaimedRewardsResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Claim unclaimed rewards hash, err := node.ClaimUnclaimedRewards(rp, nodeAddress, opts) if err != nil { diff --git a/rocketpool/api/node/commands.go b/rocketpool/api/node/commands.go deleted file mode 100644 index 32965eeae..000000000 --- a/rocketpool/api/node/commands.go +++ /dev/null @@ -1,1820 +0,0 @@ -package node - -import ( - "context" - - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage the node", - Commands: []*cli.Command{ - - { - Name: "status", - Aliases: []string{"s"}, - Usage: "Get the node's status", - UsageText: "rocketpool api node status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getStatus(c)) - return nil - - }, - }, - - { - Name: "alerts", - Aliases: []string{"al"}, - Usage: "Get active alerts from Alertmanager", - UsageText: "rocketpool api node alerts", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getAlerts(c)) - return nil - - }, - }, - - { - Name: "sync", - Aliases: []string{"y"}, - Usage: "Get the sync progress of the eth1 and eth2 clients", - UsageText: "rocketpool api node sync", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getSyncProgress(c)) - return nil - - }, - }, - - { - Name: "can-register", - Usage: "Check whether the node can be registered with Rocket Pool", - UsageText: "rocketpool api node can-register timezone-location", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - timezoneLocation, err := cliutils.ValidateTimezoneLocation("timezone location", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canRegisterNode(c, timezoneLocation)) - return nil - - }, - }, - { - Name: "register", - Aliases: []string{"r"}, - Usage: "Register the node with Rocket Pool", - UsageText: "rocketpool api node register timezone-location", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - timezoneLocation, err := cliutils.ValidateTimezoneLocation("timezone location", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(registerNode(c, timezoneLocation)) - return nil - - }, - }, - - { - Name: "can-set-primary-withdrawal-address", - Usage: "Checks if the node can set its primary withdrawal address", - UsageText: "rocketpool api node can-set-primary-withdrawal-address address confirm", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - withdrawalAddress, err := cliutils.ValidateAddress("withdrawal address", c.Args().Get(0)) - if err != nil { - return err - } - - confirm, err := cliutils.ValidateBool("confirm", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canSetPrimaryWithdrawalAddress(c, withdrawalAddress, confirm)) - return nil - - }, - }, - { - Name: "set-primary-withdrawal-address", - Usage: "Set the node's primary withdrawal address", - UsageText: "rocketpool api node set-primary-withdrawal-address address confirm", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - withdrawalAddress, err := cliutils.ValidateAddress("withdrawal address", c.Args().Get(0)) - if err != nil { - return err - } - - confirm, err := cliutils.ValidateBool("confirm", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(setPrimaryWithdrawalAddress(c, withdrawalAddress, confirm)) - return nil - - }, - }, - - { - Name: "can-confirm-primary-withdrawal-address", - Usage: "Checks if the node can confirm its primary withdrawal address", - UsageText: "rocketpool api node can-confirm-primary-withdrawal-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canConfirmPrimaryWithdrawalAddress(c)) - return nil - - }, - }, - { - Name: "confirm-primary-withdrawal-address", - Usage: "Confirms the node's primary withdrawal address if it was set back to the node address", - UsageText: "rocketpool api node confirm-primary-withdrawal-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(confirmPrimaryWithdrawalAddress(c)) - return nil - - }, - }, - - { - Name: "can-set-rpl-withdrawal-address", - Usage: "Checks if the node can set its RPL withdrawal address", - UsageText: "rocketpool api node can-set-rpl-withdrawal-address address confirm", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - withdrawalAddress, err := cliutils.ValidateAddress("withdrawal address", c.Args().Get(0)) - if err != nil { - return err - } - - confirm, err := cliutils.ValidateBool("confirm", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canSetRPLWithdrawalAddress(c, withdrawalAddress, confirm)) - return nil - - }, - }, - { - Name: "set-rpl-withdrawal-address", - Usage: "Set the node's RPL withdrawal address", - UsageText: "rocketpool api node set-rpl-withdrawal-address address confirm", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - withdrawalAddress, err := cliutils.ValidateAddress("withdrawal address", c.Args().Get(0)) - if err != nil { - return err - } - - confirm, err := cliutils.ValidateBool("confirm", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(setRPLWithdrawalAddress(c, withdrawalAddress, confirm)) - return nil - - }, - }, - - { - Name: "can-confirm-rpl-withdrawal-address", - Usage: "Checks if the node can confirm its RPL withdrawal address", - UsageText: "rocketpool api node can-confirm-rpl-withdrawal-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canConfirmRPLWithdrawalAddress(c)) - return nil - - }, - }, - { - Name: "confirm-rpl-withdrawal-address", - Usage: "Confirms the node's RPL withdrawal address if it was set back to the node address", - UsageText: "rocketpool api node confirm-rpl-withdrawal-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(confirmRPLWithdrawalAddress(c)) - return nil - - }, - }, - - { - Name: "can-set-timezone", - Usage: "Checks if the node can set its timezone location", - UsageText: "rocketpool api node can-set-timezone timezone-location", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - timezoneLocation, err := cliutils.ValidateTimezoneLocation("timezone location", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canSetTimezoneLocation(c, timezoneLocation)) - return nil - - }, - }, - { - Name: "set-timezone", - Aliases: []string{"t"}, - Usage: "Set the node's timezone location", - UsageText: "rocketpool api node set-timezone timezone-location", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - timezoneLocation, err := cliutils.ValidateTimezoneLocation("timezone location", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(setTimezoneLocation(c, timezoneLocation)) - return nil - - }, - }, - - { - Name: "can-swap-rpl", - Usage: "Check whether the node can swap old RPL for new RPL", - UsageText: "rocketpool api node can-swap-rpl amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("swap amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canNodeSwapRpl(c, amountWei)) - return nil - - }, - }, - { - Name: "swap-rpl-approve-rpl", - Aliases: []string{"p1"}, - Usage: "Approve fixed-supply RPL for swapping to new RPL", - UsageText: "rocketpool api node swap-rpl-approve-rpl amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("swap amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(approveFsRpl(c, amountWei)) - return nil - - }, - }, - { - Name: "wait-and-swap-rpl", - Aliases: []string{"p2"}, - Usage: "Swap old RPL for new RPL, waiting for the approval TX hash to be included in a block first", - UsageText: "rocketpool api node wait-and-swap-rpl amount tx-hash", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("swap amount", c.Args().Get(0)) - if err != nil { - return err - } - hash, err := cliutils.ValidateTxHash("swap amount", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(waitForApprovalAndSwapFsRpl(c, amountWei, hash)) - return nil - - }, - }, - { - Name: "get-swap-rpl-approval-gas", - Usage: "Estimate the gas cost of legacy RPL interaction approval", - UsageText: "rocketpool api node get-swap-rpl-approval-gas", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("approve amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getSwapApprovalGas(c, amountWei)) - return nil - - }, - }, - { - Name: "swap-rpl-allowance", - Usage: "Get the node's legacy RPL allowance for new RPL contract", - UsageText: "rocketpool api node swap-allowance-rpl", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(allowanceFsRpl(c)) - return nil - - }, - }, - { - Name: "swap-rpl", - Aliases: []string{"p3"}, - Usage: "Swap old RPL for new RPL", - UsageText: "rocketpool api node swap-rpl amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("swap amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(swapRpl(c, amountWei)) - return nil - - }, - }, - - { - Name: "can-stake-rpl", - Usage: "Check whether the node can stake RPL", - UsageText: "rocketpool api node can-stake-rpl amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("stake amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canNodeStakeRpl(c, amountWei)) - return nil - - }, - }, - { - Name: "stake-rpl-approve-rpl", - Aliases: []string{"k1"}, - Usage: "Approve RPL for staking against the node", - UsageText: "rocketpool api node stake-rpl-approve-rpl amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("stake amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(approveRpl(c, amountWei)) - return nil - - }, - }, - { - Name: "wait-and-stake-rpl", - Aliases: []string{"k2"}, - Usage: "Stake RPL against the node, waiting for approval tx-hash to be included in a block first", - UsageText: "rocketpool api node wait-and-stake-rpl amount tx-hash", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("stake amount", c.Args().Get(0)) - if err != nil { - return err - } - hash, err := cliutils.ValidateTxHash("tx-hash", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(waitForApprovalAndStakeRpl(c, amountWei, hash)) - return nil - - }, - }, - { - Name: "get-stake-rpl-approval-gas", - Usage: "Estimate the gas cost of new RPL interaction approval", - UsageText: "rocketpool api node get-stake-rpl-approval-gas", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("approve amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getStakeApprovalGas(c, amountWei)) - return nil - - }, - }, - { - Name: "stake-rpl-allowance", - Usage: "Get the node's RPL allowance for the staking contract", - UsageText: "rocketpool api node stake-allowance-rpl", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(allowanceRpl(c)) - return nil - - }, - }, - { - Name: "stake-rpl", - Aliases: []string{"k3"}, - Usage: "Stake RPL against the node", - UsageText: "rocketpool api node stake-rpl amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("stake amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(stakeRpl(c, amountWei)) - return nil - - }, - }, - { - Name: "can-set-rpl-locking-allowed", - Usage: "Check whether the node can set the RPL lock allowed status", - UsageText: "rocketpool api node can-set-rpl-locking-allowed caller allowed", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - allowedString := c.Args().Get(0) - allowed, err := cliutils.ValidateBool("allowed", allowedString) - if err != nil { - return err - } - - // Run - api.PrintResponse(canSetRplLockAllowed(c, allowed)) - return nil - - }, - }, - - { - Name: "set-rpl-locking-allowed", - Usage: "Sets the node RPL locking allowed status", - UsageText: "rocketpool api node set-rpl-locking-allowed caller allowed", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - allowedString := c.Args().Get(0) - allowed, err := cliutils.ValidateBool("allowed", allowedString) - if err != nil { - return err - } - - // Run - api.PrintResponse(setRplLockAllowed(c, allowed)) - return nil - - }, - }, - - { - Name: "can-set-stake-rpl-for-allowed", - Usage: "Check whether the node can set allowed status for an address to stake RPL on behalf of themself", - UsageText: "rocketpool api node can-set-stake-rpl-for-allowed caller allowed", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - - callerAddressString := c.Args().Get(0) - callerAddress, err := cliutils.ValidateAddress("caller", callerAddressString) - if err != nil { - return err - } - - allowedString := c.Args().Get(1) - allowed, err := cliutils.ValidateBool("allowed", allowedString) - if err != nil { - return err - } - - // Run - api.PrintResponse(canSetStakeRplForAllowed(c, callerAddress, allowed)) - return nil - - }, - }, - { - Name: "set-stake-rpl-for-allowed", - Aliases: []string{"kf"}, - Usage: "Sets the allowed status for an address to stake RPL on behalf of your node", - UsageText: "rocketpool api node set-stake-rpl-for-allowed caller allowed", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - - callerAddressString := c.Args().Get(0) - callerAddress, err := cliutils.ValidateAddress("caller", callerAddressString) - if err != nil { - return err - } - - allowedString := c.Args().Get(1) - allowed, err := cliutils.ValidateBool("allowed", allowedString) - if err != nil { - return err - } - - // Run - api.PrintResponse(setStakeRplForAllowed(c, callerAddress, allowed)) - - return nil - }, - }, - { - Name: "can-withdraw-credit", - Usage: "Check whether the node can withdraw credit", - UsageText: "rocketpool api node can-withdraw-credit amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("withdrawal amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canNodeWithdrawCredit(c, amountWei)) - return nil - - }, - }, - { - Name: "withdraw-credit", - Aliases: []string{"wc"}, - Usage: "Withdraw credit from the node", - UsageText: "rocketpool api node withdraw-credit amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("withdrawal amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(nodeWithdrawCredit(c, amountWei)) - return nil - - }, - }, - { - Name: "can-withdraw-eth", - Usage: "Check whether the node can withdraw ETH staked on its behalf", - UsageText: "rocketpool api node can-withdraw-eth amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("withdrawal amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canNodeWithdrawEth(c, amountWei)) - return nil - - }, - }, - { - Name: "withdraw-eth", - Aliases: []string{"i"}, - Usage: "Withdraw ETH staked on behalf of the node", - UsageText: "rocketpool api node withdraw-eth amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("withdrawal amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(nodeWithdrawEth(c, amountWei)) - return nil - - }, - }, - { - Name: "can-unstake-legacy-rpl", - Usage: "Check whether the node can withdraw legacy staked RPL", - UsageText: "rocketpool api node can-withdraw-legacy-rpl amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("unstake amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canNodeUnstakeLegacyRpl(c, amountWei)) - return nil - - }, - }, - { - Name: "unstake-legacy-rpl", - Aliases: []string{"l"}, - Usage: "Unstake legacy RPL staked against the node", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("unstake amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(nodeUnstakeLegacyRpl(c, amountWei)) - return nil - }, - }, - { - Name: "can-withdraw-rpl", - Usage: "Check whether the node can withdraw staked RPL", - UsageText: "rocketpool api node can-withdraw-rpl", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canNodeWithdrawRpl(c)) - return nil - - }, - }, - { - Name: "withdraw-rpl", - Aliases: []string{"w"}, - Usage: "Withdraw RPL staked against the node", - UsageText: "rocketpool api node withdraw-rpl", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(nodeWithdrawRpl(c)) - return nil - - }, - }, - { - Name: "can-withdraw-rpl-v131", - Usage: "Check whether the node can withdraw staked RPL", - UsageText: "rocketpool api node can-withdraw-rpl-v131 amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("withdrawal amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canNodeWithdrawRplv1_3_1(c, amountWei)) - return nil - - }, - }, - { - Name: "withdraw-rpl-v131", - Aliases: []string{"w"}, - Usage: "Withdraw RPL staked against the node", - UsageText: "rocketpool api node withdraw-rpl-v131 amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("withdrawal amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(nodeWithdrawRplv1_3_1(c, amountWei)) - return nil - - }, - }, - { - Name: "can-unstake-rpl", - Usage: "Check whether the node can unstake RPL", - UsageText: "rocketpool api node can-unstake-rpl amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - amountWei, err := cliutils.ValidatePositiveWeiAmount("unstake amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canNodeUnstakeRpl(c, amountWei)) - return nil - - }, - }, - { - Name: "unstake-rpl", - Aliases: []string{"u"}, - Usage: "Unstake RPL from the node", - UsageText: "rocketpool api node withdraw-rpl amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - amountWei, err := cliutils.ValidatePositiveWeiAmount("unstake amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(nodeUnstakeRpl(c, amountWei)) - return nil - - }, - }, - - { - Name: "can-deposit", - Usage: "Check whether the node can make a deposit. Optionally specify count to check multiple deposits.", - UsageText: "rocketpool api node can-deposit amount min-fee salt express-tickets count", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 5); err != nil { - return err - } - - amountWei, err := cliutils.ValidatePositiveWeiAmount("deposit amount", c.Args().Get(0)) - if err != nil { - return err - } - - minNodeFee, err := cliutils.ValidateFraction("minimum node fee", c.Args().Get(1)) - if err != nil { - return err - } - salt, err := cliutils.ValidateBigInt("salt", c.Args().Get(2)) - if err != nil { - return err - } - - expressTickets, err := cliutils.ValidateUint("express-tickets", c.Args().Get(3)) - if err != nil { - return err - } - - count, err := cliutils.ValidateUint("count", c.Args().Get(4)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canNodeDeposits(c, count, amountWei, minNodeFee, salt, int64(expressTickets))) - return nil - - }, - }, - { - Name: "deposit", - Aliases: []string{"d"}, - Usage: "Make a deposit and create a minipool, or just make and sign the transaction (when submit = false). Optionally specify count to make multiple deposits.", - UsageText: "rocketpool api node deposit amount min-node-fee salt use-credit-balance express-tickets submit count", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 7); err != nil { - return err - } - - amountWei, err := cliutils.ValidatePositiveWeiAmount("deposit amount", c.Args().Get(0)) - if err != nil { - return err - } - - minNodeFee, err := cliutils.ValidateFraction("minimum node fee", c.Args().Get(1)) - if err != nil { - return err - } - - salt, err := cliutils.ValidateBigInt("salt", c.Args().Get(2)) - if err != nil { - return err - } - - useCreditBalanceString := c.Args().Get(3) - useCreditBalance, err := cliutils.ValidateBool("use-credit-balance", useCreditBalanceString) - if err != nil { - return err - } - - expressTickets, err := cliutils.ValidateUint("express-tickets", c.Args().Get(4)) - if err != nil { - return err - } - submit, err := cliutils.ValidateBool("submit", c.Args().Get(5)) - if err != nil { - return err - } - - // Check if count is provided - count, err := cliutils.ValidateUint("count", c.Args().Get(6)) - if err != nil { - return err - } - - // Run - response, err := nodeDeposits(c, count, amountWei, minNodeFee, salt, useCreditBalance, int64(expressTickets), submit) - - api.PrintResponse(response, err) - return nil - - }, - }, - - { - Name: "can-send", - Usage: "Check whether the node can send ETH or tokens to an address", - UsageText: "rocketpool api node can-send amount token to", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - amountRaw, err := cliutils.ValidateEthAmount("send amount", c.Args().Get(0)) - if err != nil { - return err - } - token, err := cliutils.ValidateTokenType("token type", c.Args().Get(1)) - if err != nil { - return err - } - toAddress, err := cliutils.ValidateAddress("to address", c.Args().Get(2)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canNodeSend(c, amountRaw, token, toAddress)) - return nil - - }, - }, - { - Name: "send", - Aliases: []string{"n"}, - Usage: "Send ETH or tokens from the node account to an address", - UsageText: "rocketpool api node send amount token to", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - amountRaw, err := cliutils.ValidatePositiveEthAmount("send amount", c.Args().Get(0)) - if err != nil { - return err - } - token, err := cliutils.ValidateTokenType("token type", c.Args().Get(1)) - if err != nil { - return err - } - toAddress, err := cliutils.ValidateAddress("to address", c.Args().Get(2)) - if err != nil { - return err - } - - // Run - api.PrintResponse(nodeSend(c, amountRaw, token, toAddress)) - return nil - - }, - }, - { - Name: "send-all", - Usage: "Send the entire token balance from the node account to an address (avoids float64 rounding errors)", - UsageText: "rocketpool api node send-all token to", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - token, err := cliutils.ValidateTokenType("token type", c.Args().Get(0)) - if err != nil { - return err - } - toAddress, err := cliutils.ValidateAddress("to address", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(nodeSendAllTokens(c, token, toAddress)) - return nil - - }, - }, - - { - Name: "can-burn", - Usage: "Check whether the node can burn tokens for ETH", - UsageText: "rocketpool api node can-burn amount token", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("burn amount", c.Args().Get(0)) - if err != nil { - return err - } - token, err := cliutils.ValidateBurnableTokenType("token type", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canNodeBurn(c, amountWei, token)) - return nil - - }, - }, - { - Name: "burn", - Aliases: []string{"b"}, - Usage: "Burn tokens for ETH", - UsageText: "rocketpool api node burn amount token", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - amountWei, err := cliutils.ValidatePositiveWeiAmount("burn amount", c.Args().Get(0)) - if err != nil { - return err - } - token, err := cliutils.ValidateBurnableTokenType("token type", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(nodeBurn(c, amountWei, token)) - return nil - - }, - }, - - { - Name: "can-claim-rpl-rewards", - Usage: "Check whether the node has RPL rewards available to claim", - UsageText: "rocketpool api node can-claim-rpl-rewards", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canNodeClaimRpl(c)) - return nil - - }, - }, - { - Name: "claim-rpl-rewards", - Usage: "Claim available RPL rewards", - UsageText: "rocketpool api node claim-rpl-rewards", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(nodeClaimRpl(c)) - return nil - - }, - }, - - { - Name: "rewards", - Usage: "Get RPL rewards info", - UsageText: "rocketpool api node rewards", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getRewards(c)) - return nil - - }, - }, - - { - Name: "deposit-contract-info", - Usage: "Get information about the deposit contract specified by Rocket Pool and the Beacon Chain client", - UsageText: "rocketpool api node deposit-contract-info", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getDepositContractInfo(c)) - return nil - - }, - }, - - { - Name: "sign", - Usage: "Signs a transaction with the node's private key. The TX must be serialized as a hex string.", - UsageText: "rocketpool api node sign tx", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - data := c.Args().Get(0) - - // Run - api.PrintResponse(sign(c, data)) - return nil - - }, - }, - - { - Name: "sign-message", - Usage: "Signs an arbitrary message with the node's private key.", - UsageText: "rocketpool api node sign-message 'message'", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - message := c.Args().Get(0) - - // Run - api.PrintResponse(signMessage(c, message)) - return nil - - }, - }, - - { - Name: "is-fee-distributor-initialized", - Usage: "Check if the fee distributor contract for this node is initialized and deployed", - UsageText: "rocketpool api node is-fee-distributor-initialized", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(isFeeDistributorInitialized(c)) - return nil - - }, - }, - { - Name: "get-initialize-fee-distributor-gas", - Usage: "Estimate the cost of initializing the fee distributor", - UsageText: "rocketpool api node get-initialize-fee-distributor-gas", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getInitializeFeeDistributorGas(c)) - return nil - }, - }, - - { - Name: "initialize-fee-distributor", - Usage: "Initialize and deploy the fee distributor contract for this node", - UsageText: "rocketpool api node initialize-fee-distributor", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(initializeFeeDistributor(c)) - return nil - - }, - }, - - { - Name: "can-distribute", - Usage: "Check if distributing ETH from the node's fee distributor is possible", - UsageText: "rocketpool api node can-distribute", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canDistribute(c)) - return nil - - }, - }, - { - Name: "distribute", - Usage: "Distribute ETH from the node's fee distributor", - UsageText: "rocketpool api node distribute", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(distribute(c)) - return nil - - }, - }, - { - Name: "claim-rpl-rewards", - Usage: "Claim available RPL rewards", - UsageText: "rocketpool api node claim-rpl-rewards", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(nodeClaimRpl(c)) - return nil - - }, - }, - - { - Name: "get-rewards-info", - Usage: "Get info about your eligible rewards periods, including balances and Merkle proofs", - UsageText: "rocketpool api node get-rewards-info", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getRewardsInfo(c)) - return nil - - }, - }, - { - Name: "can-claim-rewards", - Usage: "Check if the rewards for the given intervals can be claimed", - UsageText: "rocketpool api node can-claim-rewards 0,1,2,5,6", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - indicesString := c.Args().Get(0) - - // Run - api.PrintResponse(canClaimRewards(c, indicesString)) - return nil - - }, - }, - { - Name: "claim-rewards", - Usage: "Claim rewards for the given reward intervals", - UsageText: "rocketpool api node claim-rewards 0,1,2,5,6", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - indicesString := c.Args().Get(0) - - // Run - api.PrintResponse(claimRewards(c, indicesString)) - return nil - - }, - }, - { - Name: "can-claim-and-stake-rewards", - Usage: "Check if the rewards for the given intervals can be claimed, and RPL restaked automatically", - UsageText: "rocketpool api node can-claim-and-stake-rewards 0,1,2,5,6 amount-to-restake", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - indicesString := c.Args().Get(0) - - stakeAmount, err := cliutils.ValidateBigInt("stakeAmount", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canClaimAndStakeRewards(c, indicesString, stakeAmount)) - return nil - - }, - }, - { - Name: "claim-and-stake-rewards", - Usage: "Claim rewards for the given reward intervals and restake RPL automatically", - UsageText: "rocketpool api node claim-and-stake-rewards 0,1,2,5,6 amount-to-restake", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - indicesString := c.Args().Get(0) - - stakeAmount, err := cliutils.ValidateBigInt("stakeAmount", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(claimAndStakeRewards(c, indicesString, stakeAmount)) - return nil - - }, - }, - - { - Name: "get-smoothing-pool-registration-status", - Usage: "Check whether or not the node is opted into the Smoothing Pool", - UsageText: "rocketpool api node get-smoothing-pool-registration-status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getSmoothingPoolRegistrationStatus(c)) - return nil - - }, - }, - { - Name: "can-set-smoothing-pool-status", - Usage: "Check if the node's Smoothing Pool status can be changed", - UsageText: "rocketpool api node can-set-smoothing-pool-status status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - status, err := cliutils.ValidateBool("status", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canSetSmoothingPoolStatus(c, status)) - return nil - - }, - }, - { - Name: "set-smoothing-pool-status", - Usage: "Sets the node's Smoothing Pool opt-in status", - UsageText: "rocketpool api node set-smoothing-pool-status status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - status, err := cliutils.ValidateBool("status", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(setSmoothingPoolStatus(c, status)) - return nil - - }, - }, - { - Name: "resolve-ens-name", - Usage: "Resolve an ENS name", - UsageText: "rocketpool api node resolve-ens-name name", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Run - api.PrintResponse(resolveEnsName(c, c.Args().Get(0))) - return nil - - }, - }, - { - Name: "reverse-resolve-ens-name", - Usage: "Reverse resolve an address to an ENS name", - UsageText: "rocketpool api node reverse-resolve-ens-name address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - address, err := cliutils.ValidateAddress("address", c.Args().Get(0)) - if err != nil { - return err - } - // Run - api.PrintResponse(reverseResolveEnsName(c, address)) - return nil - - }, - }, - - { - Name: "check-collateral", - Usage: "Check if the node is above the minimum collateralization threshold, including pending bond reductions", - UsageText: "rocketpool api node check-collateral", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(checkCollateral(c)) - return nil - - }, - }, - - { - Name: "get-eth-balance", - Usage: "Get the ETH balance of the node address", - UsageText: "rocketpool api node get-eth-balance", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getNodeEthBalance(c)) - return nil - - }, - }, - - { - Name: "can-send-message", - Usage: "Estimates the gas for sending a zero-value message with a payload", - UsageText: "rocketpool api node can-send-message address message", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - address, err := cliutils.ValidateAddress("address", c.Args().Get(0)) - if err != nil { - return err - } - message, err := cliutils.ValidateByteArray("message", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canSendMessage(c, address, message)) - return nil - - }, - }, - { - Name: "send-message", - Usage: "Sends a zero-value message with a payload", - UsageText: "rocketpool api node send-message address message", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - address, err := cliutils.ValidateAddress("address", c.Args().Get(0)) - if err != nil { - return err - } - message, err := cliutils.ValidateByteArray("message", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(sendMessage(c, address, message)) - return nil - - }, - }, - { - Name: "get-express-ticket-count", - Usage: "Get the number of express tickets available for the node", - UsageText: "rocketpool api node get-express-ticket-count", - Action: func(ctx context.Context, c *cli.Command) error { - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - api.PrintResponse(getExpressTicketCount(c)) - return nil - }, - }, - { - Name: "can-claim-unclaimed-rewards", - Usage: "Check if any unclaimed rewards can be sent to the node's withdrawal address", - UsageText: "rocketpool api node can-claim-unclaimed-rewards address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - // Get amount - nodeAddress, err := cliutils.ValidateAddress("address", c.Args().Get(0)) - if err != nil { - return err - } - // Run - api.PrintResponse(canClaimUnclaimedRewards(c, nodeAddress)) - return nil - - }, - }, - { - Name: "claim-unclaimed-rewards", - Usage: "Send unclaimed rewards to the node's withdrawal address", - UsageText: "rocketpool api node claim-unclaimed-rewards address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - // Get amount - nodeAddress, err := cliutils.ValidateAddress("address", c.Args().Get(0)) - if err != nil { - return err - } - // Run - api.PrintResponse(canClaimUnclaimedRewards(c, nodeAddress)) - return nil - - }, - }, - { - Name: "get-express-tickets-provisioned", - Usage: "Get the number of express tickets provisioned for the node", - UsageText: "rocketpool api node get-express-tickets-provisioned", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getExpressTicketsProvisioned(c)) - return nil - - }, - }, - { - Name: "can-provision-express-tickets", - Usage: "Check if the node's express tickets can be provisioned", - UsageText: "rocketpool api node can-provision-express-tickets", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canProvisionExpressTickets(c)) - return nil - - }, - }, - { - Name: "provision-express-tickets", - Usage: "Provision the node's express tickets", - UsageText: "rocketpool api node provision-express-tickets", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(provisionExpressTickets(c)) - return nil - - }, - }, - { - Name: "get-bond-requirement", - Usage: "Get the bond requirement for a validator", - UsageText: "rocketpool api node get-bond-requirement num-validators", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - numValidators, err := cliutils.ValidateUint("num-validators", c.Args().Get(0)) - if err != nil { - return err - } - // Run - api.PrintResponse(getBondRequirement(c, numValidators)) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/node/create-vacant-minipool.go b/rocketpool/api/node/create-vacant-minipool.go index f97a8b2f2..de75b8bbc 100644 --- a/rocketpool/api/node/create-vacant-minipool.go +++ b/rocketpool/api/node/create-vacant-minipool.go @@ -6,6 +6,8 @@ import ( "math/big" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/rocket-pool/smartnode/bindings/minipool" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/bindings/settings/protocol" @@ -16,7 +18,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services/beacon" "github.com/rocket-pool/smartnode/shared/types/api" cfgtypes "github.com/rocket-pool/smartnode/shared/types/config" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" ) @@ -153,7 +154,7 @@ func canCreateVacantMinipool(c *cli.Command, amountWei *big.Int, minNodeFee floa } -func createVacantMinipool(c *cli.Command, amountWei *big.Int, minNodeFee float64, salt *big.Int, pubkey rptypes.ValidatorPubkey) (*api.CreateVacantMinipoolResponse, error) { +func createVacantMinipool(c *cli.Command, amountWei *big.Int, minNodeFee float64, salt *big.Int, pubkey rptypes.ValidatorPubkey, opts *bind.TransactOpts) (*api.CreateVacantMinipoolResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -220,12 +221,6 @@ func createVacantMinipool(c *cli.Command, amountWei *big.Int, minNodeFee float64 scrubPeriod := time.Duration(scrubPeriodUnix) * time.Second response.ScrubPeriod = scrubPeriod - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - // Get the next minipool address and withdrawal credentials minipoolAddress, err := minipool.GetExpectedAddress(rp, nodeAccount.Address, salt, nil) if err != nil { @@ -256,12 +251,6 @@ func createVacantMinipool(c *cli.Command, amountWei *big.Int, minNodeFee float64 balanceWei := big.NewInt(0).SetUint64(validatorStatus.Balance) balanceWei.Mul(balanceWei, big.NewInt(1e9)) - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Create the minipool tx, err := node.CreateVacantMinipool(rp, amountWei, minNodeFee, pubkey, salt, minipoolAddress, balanceWei, opts) if err != nil { diff --git a/rocketpool/api/node/deposit.go b/rocketpool/api/node/deposit.go index 3c6e894f3..c3d5c9e5d 100644 --- a/rocketpool/api/node/deposit.go +++ b/rocketpool/api/node/deposit.go @@ -7,6 +7,7 @@ import ( "math/big" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing" "github.com/rocket-pool/smartnode/bindings/deposit" @@ -23,7 +24,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/services/beacon" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/rocket-pool/smartnode/shared/utils/validator" eth2types "github.com/wealdtech/go-eth2-types/v2" ) @@ -292,7 +292,7 @@ func canNodeDeposits(c *cli.Command, count uint64, amountWei *big.Int, minNodeFe } -func nodeDeposits(c *cli.Command, count uint64, amountWei *big.Int, minNodeFee float64, salt *big.Int, useCreditBalance bool, expressTicketsRequested int64, submit bool) (*api.NodeDepositsResponse, error) { +func nodeDeposits(c *cli.Command, count uint64, amountWei *big.Int, minNodeFee float64, salt *big.Int, useCreditBalance bool, expressTicketsRequested int64, submit bool, opts *bind.TransactOpts) (*api.NodeDepositsResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -369,12 +369,6 @@ func nodeDeposits(c *cli.Command, count uint64, amountWei *big.Int, minNodeFee f return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - // Set the value to the total amount needed// Get how much credit to use if useCreditBalance { remainingAmount := big.NewInt(0).Sub(amountWei, creditBalanceWei) @@ -474,12 +468,6 @@ func nodeDeposits(c *cli.Command, count uint64, amountWei *big.Int, minNodeFee f expressTicketsRequested-- } - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Do not send transaction unless requested opts.NoSend = !submit diff --git a/rocketpool/api/node/distributor.go b/rocketpool/api/node/distributor.go index dfb7e7f6c..0063db488 100644 --- a/rocketpool/api/node/distributor.go +++ b/rocketpool/api/node/distributor.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/bindings/utils/eth" "github.com/urfave/cli/v3" @@ -11,7 +13,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func isFeeDistributorInitialized(c *cli.Command) (*api.NodeIsFeeDistributorInitializedResponse, error) { @@ -96,16 +97,12 @@ func getInitializeFeeDistributorGas(c *cli.Command) (*api.NodeInitializeFeeDistr } -func initializeFeeDistributor(c *cli.Command) (*api.NodeInitializeFeeDistributorResponse, error) { +func initializeFeeDistributor(c *cli.Command, opts *bind.TransactOpts) (*api.NodeInitializeFeeDistributorResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -114,17 +111,6 @@ func initializeFeeDistributor(c *cli.Command) (*api.NodeInitializeFeeDistributor // Response response := api.NodeInitializeFeeDistributorResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Initialize the fee distributor hash, err := node.InitializeFeeDistributor(rp, opts) if err != nil { @@ -215,7 +201,7 @@ func canDistribute(c *cli.Command) (*api.NodeCanDistributeResponse, error) { } -func distribute(c *cli.Command) (*api.NodeDistributeResponse, error) { +func distribute(c *cli.Command, opts *bind.TransactOpts) (*api.NodeDistributeResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { return nil, err @@ -253,18 +239,6 @@ func distribute(c *cli.Command) (*api.NodeDistributeResponse, error) { return nil, err } - // Get gas estimates - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - hash, err := distributor.Distribute(opts) if err != nil { return nil, err diff --git a/rocketpool/api/node/express-ticket.go b/rocketpool/api/node/express-ticket.go index c60d2368e..bcc1a6d2b 100644 --- a/rocketpool/api/node/express-ticket.go +++ b/rocketpool/api/node/express-ticket.go @@ -1,12 +1,11 @@ package node import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -116,7 +115,7 @@ func canProvisionExpressTickets(c *cli.Command) (*api.CanProvisionExpressTickets } -func provisionExpressTickets(c *cli.Command) (*api.ProvisionExpressTicketsResponse, error) { +func provisionExpressTickets(c *cli.Command, opts *bind.TransactOpts) (*api.ProvisionExpressTicketsResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -143,18 +142,6 @@ func provisionExpressTickets(c *cli.Command) (*api.ProvisionExpressTicketsRespon // Response response := api.ProvisionExpressTicketsResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("error checking for nonce override: %w", err) - } - // Provision express tickets hash, err := node.ProvisionExpressTickets(rp, nodeAccount.Address, opts) if err != nil { diff --git a/rocketpool/api/node/primary-withdrawal-address.go b/rocketpool/api/node/primary-withdrawal-address.go index 27e67e12a..046f0a20b 100644 --- a/rocketpool/api/node/primary-withdrawal-address.go +++ b/rocketpool/api/node/primary-withdrawal-address.go @@ -3,13 +3,13 @@ package node import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/storage" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canSetPrimaryWithdrawalAddress(c *cli.Command, withdrawalAddress common.Address, confirm bool) (*api.CanSetNodePrimaryWithdrawalAddressResponse, error) { @@ -54,7 +54,7 @@ func canSetPrimaryWithdrawalAddress(c *cli.Command, withdrawalAddress common.Add return &response, nil } -func setPrimaryWithdrawalAddress(c *cli.Command, withdrawalAddress common.Address, confirm bool) (*api.SetNodePrimaryWithdrawalAddressResponse, error) { +func setPrimaryWithdrawalAddress(c *cli.Command, withdrawalAddress common.Address, confirm bool, opts *bind.TransactOpts) (*api.SetNodePrimaryWithdrawalAddressResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -72,18 +72,6 @@ func setPrimaryWithdrawalAddress(c *cli.Command, withdrawalAddress common.Addres // Response response := api.SetNodePrimaryWithdrawalAddressResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Get the node's account nodeAccount, err := w.GetNodeAccount() if err != nil { @@ -160,7 +148,7 @@ func canConfirmPrimaryWithdrawalAddress(c *cli.Command) (*api.CanConfirmNodePrim return &response, nil } -func confirmPrimaryWithdrawalAddress(c *cli.Command) (*api.ConfirmNodePrimaryWithdrawalAddressResponse, error) { +func confirmPrimaryWithdrawalAddress(c *cli.Command, opts *bind.TransactOpts) (*api.ConfirmNodePrimaryWithdrawalAddressResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -178,18 +166,6 @@ func confirmPrimaryWithdrawalAddress(c *cli.Command) (*api.ConfirmNodePrimaryWit // Response response := api.ConfirmNodePrimaryWithdrawalAddressResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Get the node's account nodeAccount, err := w.GetNodeAccount() if err != nil { diff --git a/rocketpool/api/node/register.go b/rocketpool/api/node/register.go index ad24bfd0e..443a54e1c 100644 --- a/rocketpool/api/node/register.go +++ b/rocketpool/api/node/register.go @@ -1,7 +1,7 @@ package node import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/bindings/settings/protocol" @@ -10,7 +10,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canRegisterNode(c *cli.Command, timezoneLocation string) (*api.CanRegisterNodeResponse, error) { @@ -84,7 +83,7 @@ func canRegisterNode(c *cli.Command, timezoneLocation string) (*api.CanRegisterN } -func registerNode(c *cli.Command, timezoneLocation string) (*api.RegisterNodeResponse, error) { +func registerNode(c *cli.Command, timezoneLocation string, opts *bind.TransactOpts) (*api.RegisterNodeResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -93,10 +92,6 @@ func registerNode(c *cli.Command, timezoneLocation string) (*api.RegisterNodeRes if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -105,18 +100,6 @@ func registerNode(c *cli.Command, timezoneLocation string) (*api.RegisterNodeRes // Response response := api.RegisterNodeResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Register node hash, err := node.RegisterNode(rp, timezoneLocation, opts) if err != nil { diff --git a/rocketpool/api/node/routes.go b/rocketpool/api/node/routes.go new file mode 100644 index 000000000..b63af6851 --- /dev/null +++ b/rocketpool/api/node/routes.go @@ -0,0 +1,997 @@ +package node + +import ( + "encoding/hex" + "fmt" + "math/big" + "net/http" + "strconv" + + "github.com/ethereum/go-ethereum/common" + rptypes "github.com/rocket-pool/smartnode/bindings/types" + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/shared/services" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +// RegisterRoutes registers the node module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/node/status", func(w http.ResponseWriter, r *http.Request) { + resp, err := getStatus(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/alerts", func(w http.ResponseWriter, r *http.Request) { + resp, err := getAlerts(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/sync", func(w http.ResponseWriter, r *http.Request) { + resp, err := getSyncProgress(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/get-eth-balance", func(w http.ResponseWriter, r *http.Request) { + resp, err := getNodeEthBalance(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/check-collateral", func(w http.ResponseWriter, r *http.Request) { + resp, err := checkCollateral(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/rewards", func(w http.ResponseWriter, r *http.Request) { + resp, err := getRewards(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/deposit-contract-info", func(w http.ResponseWriter, r *http.Request) { + resp, err := getDepositContractInfo(c) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Register --- + + mux.HandleFunc("/api/node/can-register", func(w http.ResponseWriter, r *http.Request) { + tz := r.URL.Query().Get("timezoneLocation") + resp, err := canRegisterNode(c, tz) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/register", func(w http.ResponseWriter, r *http.Request) { + tz := r.FormValue("timezoneLocation") + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := registerNode(c, tz, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Timezone --- + + mux.HandleFunc("/api/node/can-set-timezone", func(w http.ResponseWriter, r *http.Request) { + tz := r.URL.Query().Get("timezoneLocation") + resp, err := canSetTimezoneLocation(c, tz) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/set-timezone", func(w http.ResponseWriter, r *http.Request) { + tz := r.FormValue("timezoneLocation") + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setTimezoneLocation(c, tz, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Primary withdrawal address --- + + mux.HandleFunc("/api/node/can-set-primary-withdrawal-address", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(r.URL.Query().Get("address")) + confirm := r.URL.Query().Get("confirm") == "true" + resp, err := canSetPrimaryWithdrawalAddress(c, addr, confirm) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/set-primary-withdrawal-address", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(r.FormValue("address")) + confirm := r.FormValue("confirm") == "true" + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setPrimaryWithdrawalAddress(c, addr, confirm, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-confirm-primary-withdrawal-address", func(w http.ResponseWriter, r *http.Request) { + resp, err := canConfirmPrimaryWithdrawalAddress(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/confirm-primary-withdrawal-address", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := confirmPrimaryWithdrawalAddress(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- RPL withdrawal address --- + + mux.HandleFunc("/api/node/can-set-rpl-withdrawal-address", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(r.URL.Query().Get("address")) + confirm := r.URL.Query().Get("confirm") == "true" + resp, err := canSetRPLWithdrawalAddress(c, addr, confirm) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/set-rpl-withdrawal-address", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(r.FormValue("address")) + confirm := r.FormValue("confirm") == "true" + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setRPLWithdrawalAddress(c, addr, confirm, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-confirm-rpl-withdrawal-address", func(w http.ResponseWriter, r *http.Request) { + resp, err := canConfirmRPLWithdrawalAddress(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/confirm-rpl-withdrawal-address", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := confirmRPLWithdrawalAddress(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Swap RPL --- + + mux.HandleFunc("/api/node/swap-rpl-allowance", func(w http.ResponseWriter, r *http.Request) { + resp, err := allowanceFsRpl(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-swap-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canNodeSwapRpl(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/get-swap-rpl-approval-gas", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := getSwapApprovalGas(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/swap-rpl-approve-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := approveFsRpl(c, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/wait-and-swap-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + hash := common.HexToHash(r.FormValue("approvalTxHash")) + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := waitForApprovalAndSwapFsRpl(c, amountWei, hash, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/swap-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := swapRpl(c, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Stake RPL --- + + mux.HandleFunc("/api/node/stake-rpl-allowance", func(w http.ResponseWriter, r *http.Request) { + resp, err := allowanceRpl(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-stake-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canNodeStakeRpl(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/get-stake-rpl-approval-gas", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := getStakeApprovalGas(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/stake-rpl-approve-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := approveRpl(c, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/wait-and-stake-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + hash := common.HexToHash(r.FormValue("approvalTxHash")) + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := waitForApprovalAndStakeRpl(c, amountWei, hash, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/stake-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := stakeRpl(c, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- RPL locking --- + + mux.HandleFunc("/api/node/can-set-rpl-locking-allowed", func(w http.ResponseWriter, r *http.Request) { + allowed := r.URL.Query().Get("allowed") == "true" + resp, err := canSetRplLockAllowed(c, allowed) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/set-rpl-locking-allowed", func(w http.ResponseWriter, r *http.Request) { + allowed := r.FormValue("allowed") == "true" + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setRplLockAllowed(c, allowed, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Stake RPL for allowed --- + + mux.HandleFunc("/api/node/can-set-stake-rpl-for-allowed", func(w http.ResponseWriter, r *http.Request) { + caller := common.HexToAddress(r.URL.Query().Get("caller")) + allowed := r.URL.Query().Get("allowed") == "true" + resp, err := canSetStakeRplForAllowed(c, caller, allowed) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/set-stake-rpl-for-allowed", func(w http.ResponseWriter, r *http.Request) { + caller := common.HexToAddress(r.FormValue("caller")) + allowed := r.FormValue("allowed") == "true" + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setStakeRplForAllowed(c, caller, allowed, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Withdraw RPL --- + + mux.HandleFunc("/api/node/can-withdraw-rpl", func(w http.ResponseWriter, r *http.Request) { + resp, err := canNodeWithdrawRpl(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/withdraw-rpl", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := nodeWithdrawRpl(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-unstake-legacy-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canNodeUnstakeLegacyRpl(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/unstake-legacy-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := nodeUnstakeLegacyRpl(c, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-withdraw-rpl-v131", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canNodeWithdrawRplv1_3_1(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/withdraw-rpl-v131", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := nodeWithdrawRplv1_3_1(c, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-unstake-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canNodeUnstakeRpl(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/unstake-rpl", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := nodeUnstakeRpl(c, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Withdraw ETH / credit --- + + mux.HandleFunc("/api/node/can-withdraw-eth", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canNodeWithdrawEth(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/withdraw-eth", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := nodeWithdrawEth(c, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-withdraw-credit", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canNodeWithdrawCredit(c, amountWei) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/withdraw-credit", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := nodeWithdrawCredit(c, amountWei, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Deposit --- + + mux.HandleFunc("/api/node/can-deposit", func(w http.ResponseWriter, r *http.Request) { + params, err := parseDepositParams(r, false) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canNodeDeposits(c, params.count, params.amountWei, params.minFee, params.salt, params.expressTickets) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/deposit", func(w http.ResponseWriter, r *http.Request) { + params, err := parseDepositParams(r, true) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := nodeDeposits(c, params.count, params.amountWei, params.minFee, params.salt, params.useCreditBalance, params.expressTickets, params.submit, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Send / burn --- + + mux.HandleFunc("/api/node/can-send", func(w http.ResponseWriter, r *http.Request) { + amountRaw, err := parseNodeFloat64(r, "amountRaw") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + token := r.URL.Query().Get("token") + to := common.HexToAddress(r.URL.Query().Get("to")) + resp, err := canNodeSend(c, amountRaw, token, to) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/send", func(w http.ResponseWriter, r *http.Request) { + amountRaw, err := parseNodeFloat64(r, "amountRaw") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + token := r.FormValue("token") + to := common.HexToAddress(r.FormValue("to")) + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := nodeSend(c, amountRaw, token, to, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/send-all", func(w http.ResponseWriter, r *http.Request) { + token := r.FormValue("token") + to := common.HexToAddress(r.FormValue("to")) + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := nodeSendAllTokens(c, token, to, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-burn", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + token := r.URL.Query().Get("token") + resp, err := canNodeBurn(c, amountWei, token) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/burn", func(w http.ResponseWriter, r *http.Request) { + amountWei, err := parseNodeBigInt(r, "amountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + token := r.FormValue("token") + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := nodeBurn(c, amountWei, token, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- RPL claim --- + + mux.HandleFunc("/api/node/can-claim-rpl-rewards", func(w http.ResponseWriter, r *http.Request) { + resp, err := canNodeClaimRpl(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/claim-rpl-rewards", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := nodeClaimRpl(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Fee distributor --- + + mux.HandleFunc("/api/node/is-fee-distributor-initialized", func(w http.ResponseWriter, r *http.Request) { + resp, err := isFeeDistributorInitialized(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/get-initialize-fee-distributor-gas", func(w http.ResponseWriter, r *http.Request) { + resp, err := getInitializeFeeDistributorGas(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/initialize-fee-distributor", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := initializeFeeDistributor(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-distribute", func(w http.ResponseWriter, r *http.Request) { + resp, err := canDistribute(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/distribute", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := distribute(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Interval rewards --- + + mux.HandleFunc("/api/node/get-rewards-info", func(w http.ResponseWriter, r *http.Request) { + resp, err := getRewardsInfo(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-claim-rewards", func(w http.ResponseWriter, r *http.Request) { + indices := r.URL.Query().Get("indices") + resp, err := canClaimRewards(c, indices) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/claim-rewards", func(w http.ResponseWriter, r *http.Request) { + indices := r.FormValue("indices") + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := claimRewards(c, indices, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-claim-and-stake-rewards", func(w http.ResponseWriter, r *http.Request) { + indices := r.URL.Query().Get("indices") + stakeAmount, err := parseNodeBigInt(r, "stakeAmount") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canClaimAndStakeRewards(c, indices, stakeAmount) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/claim-and-stake-rewards", func(w http.ResponseWriter, r *http.Request) { + indices := r.FormValue("indices") + stakeAmount, err := parseNodeBigInt(r, "stakeAmount") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := claimAndStakeRewards(c, indices, stakeAmount, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Smoothing pool --- + + mux.HandleFunc("/api/node/get-smoothing-pool-registration-status", func(w http.ResponseWriter, r *http.Request) { + resp, err := getSmoothingPoolRegistrationStatus(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-set-smoothing-pool-status", func(w http.ResponseWriter, r *http.Request) { + status := r.URL.Query().Get("status") == "true" + resp, err := canSetSmoothingPoolStatus(c, status) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/set-smoothing-pool-status", func(w http.ResponseWriter, r *http.Request) { + status := r.FormValue("status") == "true" + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setSmoothingPoolStatus(c, status, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- ENS --- + + mux.HandleFunc("/api/node/resolve-ens-name", func(w http.ResponseWriter, r *http.Request) { + name := r.URL.Query().Get("name") + resp, err := resolveEnsName(c, name) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/reverse-resolve-ens-name", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(r.URL.Query().Get("address")) + resp, err := reverseResolveEnsName(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Sign --- + + mux.HandleFunc("/api/node/sign-message", func(w http.ResponseWriter, r *http.Request) { + message := r.FormValue("message") + resp, err := signMessage(c, message) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/sign", func(w http.ResponseWriter, r *http.Request) { + serializedTx := r.FormValue("serializedTx") + resp, err := sign(c, serializedTx) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Vacant minipool --- + + mux.HandleFunc("/api/node/can-create-vacant-minipool", func(w http.ResponseWriter, r *http.Request) { + params, err := parseVacantMinipoolParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canCreateVacantMinipool(c, params.amountWei, params.minFee, params.salt, params.pubkey) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/create-vacant-minipool", func(w http.ResponseWriter, r *http.Request) { + params, err := parseVacantMinipoolParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := createVacantMinipool(c, params.amountWei, params.minFee, params.salt, params.pubkey, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Send message --- + + mux.HandleFunc("/api/node/can-send-message", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(r.URL.Query().Get("address")) + msgBytes, err := hex.DecodeString(r.URL.Query().Get("message")) + if err != nil { + apiutils.WriteErrorResponse(w, fmt.Errorf("invalid message hex: %w", err)) + return + } + resp, err := canSendMessage(c, addr, msgBytes) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/send-message", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(r.FormValue("address")) + msgBytes, err := hex.DecodeString(r.FormValue("message")) + if err != nil { + apiutils.WriteErrorResponse(w, fmt.Errorf("invalid message hex: %w", err)) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := sendMessage(c, addr, msgBytes, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Express tickets --- + + mux.HandleFunc("/api/node/get-express-ticket-count", func(w http.ResponseWriter, r *http.Request) { + resp, err := getExpressTicketCount(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/get-express-tickets-provisioned", func(w http.ResponseWriter, r *http.Request) { + resp, err := getExpressTicketsProvisioned(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/can-provision-express-tickets", func(w http.ResponseWriter, r *http.Request) { + resp, err := canProvisionExpressTickets(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/provision-express-tickets", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := provisionExpressTickets(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Unclaimed rewards --- + + mux.HandleFunc("/api/node/can-claim-unclaimed-rewards", func(w http.ResponseWriter, r *http.Request) { + nodeAddr := common.HexToAddress(r.URL.Query().Get("nodeAddress")) + resp, err := canClaimUnclaimedRewards(c, nodeAddr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/node/claim-unclaimed-rewards", func(w http.ResponseWriter, r *http.Request) { + nodeAddr := common.HexToAddress(r.FormValue("nodeAddress")) + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := claimUnclaimedRewards(c, nodeAddr, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // --- Bond requirement --- + + mux.HandleFunc("/api/node/get-bond-requirement", func(w http.ResponseWriter, r *http.Request) { + numValidators, err := strconv.ParseUint(r.URL.Query().Get("numValidators"), 10, 64) + if err != nil { + apiutils.WriteErrorResponse(w, fmt.Errorf("invalid numValidators: %w", err)) + return + } + resp, err := getBondRequirement(c, numValidators) + apiutils.WriteResponse(w, resp, err) + }) +} + +// --- Helper types and functions --- + +type depositParams struct { + count uint64 + amountWei *big.Int + minFee float64 + salt *big.Int + expressTickets int64 + useCreditBalance bool + submit bool +} + +func parseDepositParams(r *http.Request, includeExecuteParams bool) (depositParams, error) { + var p depositParams + var err error + + p.amountWei, err = parseNodeBigInt(r, "amountWei") + if err != nil { + return p, fmt.Errorf("invalid amountWei: %w", err) + } + + minFeeStr := r.URL.Query().Get("minFee") + if minFeeStr == "" { + minFeeStr = r.FormValue("minFee") + } + p.minFee, err = strconv.ParseFloat(minFeeStr, 64) + if err != nil { + return p, fmt.Errorf("invalid minFee: %w", err) + } + + p.salt, err = parseNodeBigInt(r, "salt") + if err != nil { + return p, fmt.Errorf("invalid salt: %w", err) + } + + expressStr := r.URL.Query().Get("expressTickets") + if expressStr == "" { + expressStr = r.FormValue("expressTickets") + } + p.expressTickets, err = strconv.ParseInt(expressStr, 10, 64) + if err != nil { + return p, fmt.Errorf("invalid expressTickets: %w", err) + } + + countStr := r.URL.Query().Get("count") + if countStr == "" { + countStr = r.FormValue("count") + } + p.count, err = strconv.ParseUint(countStr, 10, 64) + if err != nil { + return p, fmt.Errorf("invalid count: %w", err) + } + + if includeExecuteParams { + p.useCreditBalance = r.FormValue("useCreditBalance") == "true" + p.submit = r.FormValue("submit") == "true" + } + + return p, nil +} + +type vacantMinipoolParams struct { + amountWei *big.Int + minFee float64 + salt *big.Int + pubkey rptypes.ValidatorPubkey +} + +func parseVacantMinipoolParams(r *http.Request) (vacantMinipoolParams, error) { + var p vacantMinipoolParams + var err error + + raw := r.URL.Query().Get("amountWei") + if raw == "" { + raw = r.FormValue("amountWei") + } + p.amountWei, _ = new(big.Int).SetString(raw, 10) + if p.amountWei == nil { + return p, fmt.Errorf("invalid amountWei: %s", raw) + } + + minFeeStr := r.URL.Query().Get("minFee") + if minFeeStr == "" { + minFeeStr = r.FormValue("minFee") + } + p.minFee, err = strconv.ParseFloat(minFeeStr, 64) + if err != nil { + return p, fmt.Errorf("invalid minFee: %w", err) + } + + saltStr := r.URL.Query().Get("salt") + if saltStr == "" { + saltStr = r.FormValue("salt") + } + p.salt, _ = new(big.Int).SetString(saltStr, 10) + if p.salt == nil { + return p, fmt.Errorf("invalid salt: %s", saltStr) + } + + pubkeyStr := r.URL.Query().Get("pubkey") + if pubkeyStr == "" { + pubkeyStr = r.FormValue("pubkey") + } + pubkeyBytes, err := hex.DecodeString(pubkeyStr) + if err != nil { + return p, fmt.Errorf("invalid pubkey hex: %w", err) + } + if len(pubkeyBytes) != len(p.pubkey) { + return p, fmt.Errorf("pubkey must be %d bytes, got %d", len(p.pubkey), len(pubkeyBytes)) + } + copy(p.pubkey[:], pubkeyBytes) + + return p, nil +} + +func parseNodeBigInt(r *http.Request, name string) (*big.Int, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + v, ok := new(big.Int).SetString(raw, 10) + if !ok { + return nil, fmt.Errorf("invalid %s: %s", name, raw) + } + return v, nil +} + +func parseNodeFloat64(r *http.Request, name string) (float64, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + return strconv.ParseFloat(raw, 64) +} diff --git a/rocketpool/api/node/rpl-withdrawal-address.go b/rocketpool/api/node/rpl-withdrawal-address.go index e42a28b55..1a91a99aa 100644 --- a/rocketpool/api/node/rpl-withdrawal-address.go +++ b/rocketpool/api/node/rpl-withdrawal-address.go @@ -1,9 +1,9 @@ package node import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/bindings/storage" @@ -12,7 +12,6 @@ import ( "golang.org/x/sync/errgroup" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canSetRPLWithdrawalAddress(c *cli.Command, withdrawalAddress common.Address, confirm bool) (*api.CanSetNodeRPLWithdrawalAddressResponse, error) { @@ -103,7 +102,7 @@ func canSetRPLWithdrawalAddress(c *cli.Command, withdrawalAddress common.Address return &response, nil } -func setRPLWithdrawalAddress(c *cli.Command, withdrawalAddress common.Address, confirm bool) (*api.SetNodeRPLWithdrawalAddressResponse, error) { +func setRPLWithdrawalAddress(c *cli.Command, withdrawalAddress common.Address, confirm bool, opts *bind.TransactOpts) (*api.SetNodeRPLWithdrawalAddressResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err @@ -120,18 +119,6 @@ func setRPLWithdrawalAddress(c *cli.Command, withdrawalAddress common.Address, c // Response response := api.SetNodeRPLWithdrawalAddressResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Get the node's account nodeAccount, err := w.GetNodeAccount() if err != nil { @@ -200,7 +187,7 @@ func canConfirmRPLWithdrawalAddress(c *cli.Command) (*api.CanConfirmNodeRPLWithd return &response, nil } -func confirmRPLWithdrawalAddress(c *cli.Command) (*api.ConfirmNodeRPLWithdrawalAddressResponse, error) { +func confirmRPLWithdrawalAddress(c *cli.Command, opts *bind.TransactOpts) (*api.ConfirmNodeRPLWithdrawalAddressResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err @@ -217,18 +204,6 @@ func confirmRPLWithdrawalAddress(c *cli.Command) (*api.ConfirmNodeRPLWithdrawalA // Response response := api.ConfirmNodeRPLWithdrawalAddressResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Get the node's account nodeAccount, err := w.GetNodeAccount() if err != nil { diff --git a/rocketpool/api/node/send-message.go b/rocketpool/api/node/send-message.go index 3d7a87da7..5d114e834 100644 --- a/rocketpool/api/node/send-message.go +++ b/rocketpool/api/node/send-message.go @@ -5,10 +5,10 @@ import ( "github.com/rocket-pool/smartnode/bindings/utils/eth" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -47,7 +47,7 @@ func canSendMessage(c *cli.Command, address common.Address, message []byte) (*ap } -func sendMessage(c *cli.Command, address common.Address, message []byte) (*api.NodeSendMessageResponse, error) { +func sendMessage(c *cli.Command, address common.Address, message []byte, opts *bind.TransactOpts) (*api.NodeSendMessageResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -65,18 +65,6 @@ func sendMessage(c *cli.Command, address common.Address, message []byte) (*api.N // Response response := api.NodeSendMessageResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Send the message hash, err := eth.SendTransaction(ec, address, w.GetChainID(), message, true, opts) if err != nil { diff --git a/rocketpool/api/node/send.go b/rocketpool/api/node/send.go index 24bea4a6e..663481176 100644 --- a/rocketpool/api/node/send.go +++ b/rocketpool/api/node/send.go @@ -7,6 +7,7 @@ import ( "math/big" "strings" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/tokens" "github.com/rocket-pool/smartnode/bindings/utils/eth" @@ -14,7 +15,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canNodeSend(c *cli.Command, amountRaw float64, token string, to common.Address) (*api.CanNodeSendResponse, error) { @@ -203,7 +203,7 @@ func canNodeSend(c *cli.Command, amountRaw float64, token string, to common.Addr } -func nodeSend(c *cli.Command, amountRaw float64, token string, to common.Address) (*api.NodeSendResponse, error) { +func nodeSend(c *cli.Command, amountRaw float64, token string, to common.Address, opts *bind.TransactOpts) (*api.NodeSendResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -225,18 +225,6 @@ func nodeSend(c *cli.Command, amountRaw float64, token string, to common.Address // Response response := api.NodeSendResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Handle explicit token addresses if strings.HasPrefix(token, "0x") { tokenAddress := common.HexToAddress(token) @@ -317,7 +305,7 @@ func nodeSend(c *cli.Command, amountRaw float64, token string, to common.Address // the recipient, using the exact *big.Int balance to avoid float64 rounding // errors that would cause "transfer amount exceeds balance" failures. // ETH is not supported here; use nodeSend with a pre-computed amount instead. -func nodeSendAllTokens(c *cli.Command, token string, to common.Address) (*api.NodeSendResponse, error) { +func nodeSendAllTokens(c *cli.Command, token string, to common.Address, opts *bind.TransactOpts) (*api.NodeSendResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -345,18 +333,6 @@ func nodeSendAllTokens(c *cli.Command, token string, to common.Address) (*api.No return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Handle explicit token addresses if strings.HasPrefix(token, "0x") { tokenAddress := common.HexToAddress(token) diff --git a/rocketpool/api/node/set-rpl-lock-allowed.go b/rocketpool/api/node/set-rpl-lock-allowed.go index 750bcdffc..35947dde8 100644 --- a/rocketpool/api/node/set-rpl-lock-allowed.go +++ b/rocketpool/api/node/set-rpl-lock-allowed.go @@ -1,14 +1,13 @@ package node import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/node" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canSetRplLockAllowed(c *cli.Command, allowed bool) (*api.CanSetRplLockingAllowedResponse, error) { @@ -63,7 +62,7 @@ func canSetRplLockAllowed(c *cli.Command, allowed bool) (*api.CanSetRplLockingAl } -func setRplLockAllowed(c *cli.Command, allowed bool) (*api.SetRplLockingAllowedResponse, error) { +func setRplLockAllowed(c *cli.Command, allowed bool, opts *bind.TransactOpts) (*api.SetRplLockingAllowedResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -87,14 +86,6 @@ func setRplLockAllowed(c *cli.Command, allowed bool) (*api.SetRplLockingAllowedR response := api.SetRplLockingAllowedResponse{} // Stake RPL - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } hash, err := node.SetRPLLockingAllowed(rp, account.Address, allowed, opts) if err != nil { return nil, err diff --git a/rocketpool/api/node/set-stake-rpl-for-allowed.go b/rocketpool/api/node/set-stake-rpl-for-allowed.go index 562537a6b..ddf6fdb62 100644 --- a/rocketpool/api/node/set-stake-rpl-for-allowed.go +++ b/rocketpool/api/node/set-stake-rpl-for-allowed.go @@ -1,15 +1,13 @@ package node import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/node" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canSetStakeRplForAllowed(c *cli.Command, caller common.Address, allowed bool) (*api.CanSetStakeRplForAllowedResponse, error) { @@ -47,16 +45,12 @@ func canSetStakeRplForAllowed(c *cli.Command, caller common.Address, allowed boo } -func setStakeRplForAllowed(c *cli.Command, caller common.Address, allowed bool) (*api.SetStakeRplForAllowedResponse, error) { +func setStakeRplForAllowed(c *cli.Command, caller common.Address, allowed bool, opts *bind.TransactOpts) (*api.SetStakeRplForAllowedResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -66,14 +60,6 @@ func setStakeRplForAllowed(c *cli.Command, caller common.Address, allowed bool) response := api.SetStakeRplForAllowedResponse{} // Stake RPL - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } hash, err := node.SetStakeRPLForAllowed(rp, caller, allowed, opts) if err != nil { return nil, err diff --git a/rocketpool/api/node/set-timezone.go b/rocketpool/api/node/set-timezone.go index 4ac633150..9a2a95105 100644 --- a/rocketpool/api/node/set-timezone.go +++ b/rocketpool/api/node/set-timezone.go @@ -1,15 +1,15 @@ package node import ( - "fmt" _ "time/tzdata" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/rocket-pool/smartnode/bindings/node" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canSetTimezoneLocation(c *cli.Command, timezoneLocation string) (*api.CanSetNodeTimezoneResponse, error) { @@ -45,16 +45,12 @@ func canSetTimezoneLocation(c *cli.Command, timezoneLocation string) (*api.CanSe } -func setTimezoneLocation(c *cli.Command, timezoneLocation string) (*api.SetNodeTimezoneResponse, error) { +func setTimezoneLocation(c *cli.Command, timezoneLocation string, opts *bind.TransactOpts) (*api.SetNodeTimezoneResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -63,18 +59,6 @@ func setTimezoneLocation(c *cli.Command, timezoneLocation string) (*api.SetNodeT // Response response := api.SetNodeTimezoneResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Set timezone location hash, err := node.SetTimezoneLocation(rp, timezoneLocation, opts) if err != nil { diff --git a/rocketpool/api/node/smoothing-pool.go b/rocketpool/api/node/smoothing-pool.go index c06e34ce7..a1bc9d6b7 100644 --- a/rocketpool/api/node/smoothing-pool.go +++ b/rocketpool/api/node/smoothing-pool.go @@ -4,13 +4,14 @@ import ( "context" "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/bindings/rewards" rocketpoolapi "github.com/rocket-pool/smartnode/bindings/rocketpool" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/services/rocketpool" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/rocket-pool/smartnode/shared/utils/validator" "github.com/urfave/cli/v3" ) @@ -112,7 +113,7 @@ func canSetSmoothingPoolStatus(c *cli.Command, status bool) (*api.CanSetSmoothin } -func setSmoothingPoolStatus(c *cli.Command, status bool) (*api.SetSmoothingPoolRegistrationStatusResponse, error) { +func setSmoothingPoolStatus(c *cli.Command, status bool, opts *bind.TransactOpts) (*api.SetSmoothingPoolRegistrationStatusResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -145,18 +146,6 @@ func setSmoothingPoolStatus(c *cli.Command, status bool) (*api.SetSmoothingPoolR // Response response := api.SetSmoothingPoolRegistrationStatusResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Get node account and distributor address nodeAccount, err := w.GetNodeAccount() if err != nil { diff --git a/rocketpool/api/node/stake-rpl.go b/rocketpool/api/node/stake-rpl.go index 35928b784..6ed4fc8a9 100644 --- a/rocketpool/api/node/stake-rpl.go +++ b/rocketpool/api/node/stake-rpl.go @@ -1,9 +1,9 @@ package node import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/node" @@ -13,7 +13,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canNodeStakeRpl(c *cli.Command, amountWei *big.Int) (*api.CanNodeStakeRplResponse, error) { @@ -144,16 +143,12 @@ func allowanceRpl(c *cli.Command) (*api.NodeStakeRplAllowanceResponse, error) { return &response, nil } -func approveRpl(c *cli.Command, amountWei *big.Int) (*api.NodeStakeRplApproveResponse, error) { +func approveRpl(c *cli.Command, amountWei *big.Int, opts *bind.TransactOpts) (*api.NodeStakeRplApproveResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -169,14 +164,6 @@ func approveRpl(c *cli.Command, amountWei *big.Int) (*api.NodeStakeRplApproveRes } // Approve RPL allowance - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } hash, err := tokens.ApproveRPL(rp, *rocketNodeStakingAddress, amountWei, opts) if err != nil { return nil, err @@ -189,7 +176,7 @@ func approveRpl(c *cli.Command, amountWei *big.Int) (*api.NodeStakeRplApproveRes } -func waitForApprovalAndStakeRpl(c *cli.Command, amountWei *big.Int, hash common.Hash) (*api.NodeStakeRplStakeResponse, error) { +func waitForApprovalAndStakeRpl(c *cli.Command, amountWei *big.Int, hash common.Hash, opts *bind.TransactOpts) (*api.NodeStakeRplStakeResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -207,20 +194,16 @@ func waitForApprovalAndStakeRpl(c *cli.Command, amountWei *big.Int, hash common. } // Perform the stake - return stakeRpl(c, amountWei) + return stakeRpl(c, amountWei, opts) } -func stakeRpl(c *cli.Command, amountWei *big.Int) (*api.NodeStakeRplStakeResponse, error) { +func stakeRpl(c *cli.Command, amountWei *big.Int, opts *bind.TransactOpts) (*api.NodeStakeRplStakeResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -230,14 +213,6 @@ func stakeRpl(c *cli.Command, amountWei *big.Int) (*api.NodeStakeRplStakeRespons response := api.NodeStakeRplStakeResponse{} // Stake RPL - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } hash, err := node.StakeRPL(rp, amountWei, opts) if err != nil { return nil, err diff --git a/rocketpool/api/node/swap-rpl.go b/rocketpool/api/node/swap-rpl.go index 03d5b42a5..74e2d2dbb 100644 --- a/rocketpool/api/node/swap-rpl.go +++ b/rocketpool/api/node/swap-rpl.go @@ -1,9 +1,9 @@ package node import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/tokens" "github.com/rocket-pool/smartnode/bindings/utils" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canNodeSwapRpl(c *cli.Command, amountWei *big.Int) (*api.CanNodeSwapRplResponse, error) { @@ -145,7 +144,7 @@ func getSwapApprovalGas(c *cli.Command, amountWei *big.Int) (*api.NodeSwapRplApp return &response, nil } -func approveFsRpl(c *cli.Command, amountWei *big.Int) (*api.NodeSwapRplApproveResponse, error) { +func approveFsRpl(c *cli.Command, amountWei *big.Int, opts *bind.TransactOpts) (*api.NodeSwapRplApproveResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -154,10 +153,6 @@ func approveFsRpl(c *cli.Command, amountWei *big.Int) (*api.NodeSwapRplApproveRe if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -173,14 +168,6 @@ func approveFsRpl(c *cli.Command, amountWei *big.Int) (*api.NodeSwapRplApproveRe } // Approve fixed-supply RPL allowance - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } if hash, err := tokens.ApproveFixedSupplyRPL(rp, *rocketTokenRPLAddress, amountWei, opts); err != nil { return nil, err } else { @@ -192,7 +179,7 @@ func approveFsRpl(c *cli.Command, amountWei *big.Int) (*api.NodeSwapRplApproveRe } -func waitForApprovalAndSwapFsRpl(c *cli.Command, amountWei *big.Int, hash common.Hash) (*api.NodeSwapRplSwapResponse, error) { +func waitForApprovalAndSwapFsRpl(c *cli.Command, amountWei *big.Int, hash common.Hash, opts *bind.TransactOpts) (*api.NodeSwapRplSwapResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -212,20 +199,16 @@ func waitForApprovalAndSwapFsRpl(c *cli.Command, amountWei *big.Int, hash common return nil, err } - return swapRpl(c, amountWei) + return swapRpl(c, amountWei, opts) } -func swapRpl(c *cli.Command, amountWei *big.Int) (*api.NodeSwapRplSwapResponse, error) { +func swapRpl(c *cli.Command, amountWei *big.Int, opts *bind.TransactOpts) (*api.NodeSwapRplSwapResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -235,14 +218,6 @@ func swapRpl(c *cli.Command, amountWei *big.Int) (*api.NodeSwapRplSwapResponse, response := api.NodeSwapRplSwapResponse{} // Swap fixed-supply RPL for RPL - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } if hash, err := tokens.SwapFixedSupplyRPLForRPL(rp, amountWei, opts); err != nil { return nil, err } else { diff --git a/rocketpool/api/node/unstake-rpl.go b/rocketpool/api/node/unstake-rpl.go index a5459bae6..4a2d0d542 100644 --- a/rocketpool/api/node/unstake-rpl.go +++ b/rocketpool/api/node/unstake-rpl.go @@ -1,9 +1,9 @@ package node import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/node" "github.com/urfave/cli/v3" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canNodeUnstakeRpl(c *cli.Command, amountWei *big.Int) (*api.CanNodeUnstakeRplResponse, error) { @@ -104,16 +103,12 @@ func canNodeUnstakeRpl(c *cli.Command, amountWei *big.Int) (*api.CanNodeUnstakeR } -func nodeUnstakeRpl(c *cli.Command, amountWei *big.Int) (*api.NodeUnstakeRplResponse, error) { +func nodeUnstakeRpl(c *cli.Command, amountWei *big.Int, opts *bind.TransactOpts) (*api.NodeUnstakeRplResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -122,17 +117,6 @@ func nodeUnstakeRpl(c *cli.Command, amountWei *big.Int) (*api.NodeUnstakeRplResp // Response response := api.NodeUnstakeRplResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } var hash common.Hash // Withdraw RPL hash, err = node.UnstakeRPL(rp, amountWei, opts) diff --git a/rocketpool/api/node/withdraw-credit.go b/rocketpool/api/node/withdraw-credit.go index 2808a3ed9..42c07e83b 100644 --- a/rocketpool/api/node/withdraw-credit.go +++ b/rocketpool/api/node/withdraw-credit.go @@ -1,16 +1,16 @@ package node import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/rocket-pool/smartnode/bindings/node" "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canNodeWithdrawCredit(c *cli.Command, amountWei *big.Int) (*api.CanNodeWithdrawCreditResponse, error) { @@ -74,16 +74,12 @@ func canNodeWithdrawCredit(c *cli.Command, amountWei *big.Int) (*api.CanNodeWith } -func nodeWithdrawCredit(c *cli.Command, amountWei *big.Int) (*api.NodeWithdrawCreditResponse, error) { +func nodeWithdrawCredit(c *cli.Command, amountWei *big.Int, opts *bind.TransactOpts) (*api.NodeWithdrawCreditResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -92,18 +88,6 @@ func nodeWithdrawCredit(c *cli.Command, amountWei *big.Int) (*api.NodeWithdrawCr // Response response := api.NodeWithdrawCreditResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Withdraw credit tx, err := node.WithdrawCredit(rp, amountWei, opts) if err != nil { diff --git a/rocketpool/api/node/withdraw-eth.go b/rocketpool/api/node/withdraw-eth.go index ebe0ab628..f9dfd5f3a 100644 --- a/rocketpool/api/node/withdraw-eth.go +++ b/rocketpool/api/node/withdraw-eth.go @@ -1,16 +1,16 @@ package node import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/rocket-pool/smartnode/bindings/node" "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canNodeWithdrawEth(c *cli.Command, amountWei *big.Int) (*api.CanNodeWithdrawEthResponse, error) { @@ -84,7 +84,7 @@ func canNodeWithdrawEth(c *cli.Command, amountWei *big.Int) (*api.CanNodeWithdra } -func nodeWithdrawEth(c *cli.Command, amountWei *big.Int) (*api.NodeWithdrawRplResponse, error) { +func nodeWithdrawEth(c *cli.Command, amountWei *big.Int, opts *bind.TransactOpts) (*api.NodeWithdrawRplResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -102,24 +102,12 @@ func nodeWithdrawEth(c *cli.Command, amountWei *big.Int) (*api.NodeWithdrawRplRe // Response response := api.NodeWithdrawRplResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - // Get node account nodeAccount, err := w.GetNodeAccount() if err != nil { return nil, err } - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Withdraw ETH tx, err := node.WithdrawEth(rp, nodeAccount.Address, amountWei, opts) if err != nil { diff --git a/rocketpool/api/node/withdraw-legacy-rpl.go b/rocketpool/api/node/withdraw-legacy-rpl.go index dfcd519ce..d26d75316 100644 --- a/rocketpool/api/node/withdraw-legacy-rpl.go +++ b/rocketpool/api/node/withdraw-legacy-rpl.go @@ -1,9 +1,9 @@ package node import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/node" "github.com/urfave/cli/v3" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canNodeUnstakeLegacyRpl(c *cli.Command, amountWei *big.Int) (*api.CanNodeUnstakeLegacyRplResponse, error) { @@ -113,16 +112,12 @@ func canNodeUnstakeLegacyRpl(c *cli.Command, amountWei *big.Int) (*api.CanNodeUn } -func nodeUnstakeLegacyRpl(c *cli.Command, amountWei *big.Int) (*api.NodeUnstakeLegacyRplResponse, error) { +func nodeUnstakeLegacyRpl(c *cli.Command, amountWei *big.Int, opts *bind.TransactOpts) (*api.NodeUnstakeLegacyRplResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -131,17 +126,6 @@ func nodeUnstakeLegacyRpl(c *cli.Command, amountWei *big.Int) (*api.NodeUnstakeL // Response response := api.NodeUnstakeLegacyRplResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } var hash common.Hash // Unstake legacy RPL hash, err = node.UnstakeLegacyRPL(rp, amountWei, opts) diff --git a/rocketpool/api/node/withdraw-rpl.go b/rocketpool/api/node/withdraw-rpl.go index 0c2b666c5..3bd444c07 100644 --- a/rocketpool/api/node/withdraw-rpl.go +++ b/rocketpool/api/node/withdraw-rpl.go @@ -2,10 +2,10 @@ package node import ( "context" - "fmt" "math/big" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" node131 "github.com/rocket-pool/smartnode/bindings/legacy/v1.3.1/node" "github.com/rocket-pool/smartnode/bindings/node" @@ -15,7 +15,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canNodeWithdrawRpl(c *cli.Command) (*api.CanNodeWithdrawRplResponse, error) { @@ -129,16 +128,12 @@ func canNodeWithdrawRpl(c *cli.Command) (*api.CanNodeWithdrawRplResponse, error) } -func nodeWithdrawRpl(c *cli.Command) (*api.NodeWithdrawRplResponse, error) { +func nodeWithdrawRpl(c *cli.Command, opts *bind.TransactOpts) (*api.NodeWithdrawRplResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -147,17 +142,6 @@ func nodeWithdrawRpl(c *cli.Command) (*api.NodeWithdrawRplResponse, error) { // Response response := api.NodeWithdrawRplResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } var hash common.Hash // Withdraw RPL hash, err = node.WithdrawRPL(rp, opts) @@ -310,7 +294,7 @@ func canNodeWithdrawRplv1_3_1(c *cli.Command, amountWei *big.Int) (*api.CanNodeW } // Used if saturn is not deployed (v1.3.1) -func nodeWithdrawRplv1_3_1(c *cli.Command, amountWei *big.Int) (*api.NodeWithdrawRplResponse, error) { +func nodeWithdrawRplv1_3_1(c *cli.Command, amountWei *big.Int, opts *bind.TransactOpts) (*api.NodeWithdrawRplResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { @@ -334,17 +318,6 @@ func nodeWithdrawRplv1_3_1(c *cli.Command, amountWei *big.Int) (*api.NodeWithdra // Response response := api.NodeWithdrawRplResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } var hash common.Hash // Withdraw RPL hash, err = node131.WithdrawRPL(rp, nodeAccount.Address, amountWei, opts) diff --git a/rocketpool/api/odao/cancel-proposal.go b/rocketpool/api/odao/cancel-proposal.go index f57513e6c..9976f126c 100644 --- a/rocketpool/api/odao/cancel-proposal.go +++ b/rocketpool/api/odao/cancel-proposal.go @@ -2,7 +2,8 @@ package odao import ( "bytes" - "fmt" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao" "github.com/rocket-pool/smartnode/bindings/dao/trustednode" @@ -12,7 +13,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canCancelProposal(c *cli.Command, proposalId uint64) (*api.CanCancelTNDAOProposalResponse, error) { @@ -91,16 +91,12 @@ func canCancelProposal(c *cli.Command, proposalId uint64) (*api.CanCancelTNDAOPr } -func cancelProposal(c *cli.Command, proposalId uint64) (*api.CancelTNDAOProposalResponse, error) { +func cancelProposal(c *cli.Command, proposalId uint64, opts *bind.TransactOpts) (*api.CancelTNDAOProposalResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -109,18 +105,6 @@ func cancelProposal(c *cli.Command, proposalId uint64) (*api.CancelTNDAOProposal // Response response := api.CancelTNDAOProposalResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Cancel proposal hash, err := trustednode.CancelProposal(rp, proposalId, opts) if err != nil { diff --git a/rocketpool/api/odao/commands.go b/rocketpool/api/odao/commands.go deleted file mode 100644 index 92a35723f..000000000 --- a/rocketpool/api/odao/commands.go +++ /dev/null @@ -1,1140 +0,0 @@ -package odao - -import ( - "context" - - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage the Rocket Pool oracle DAO", - Commands: []*cli.Command{ - - { - Name: "status", - Aliases: []string{"s"}, - Usage: "Get oracle DAO status", - UsageText: "rocketpool api odao status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getStatus(c)) - return nil - - }, - }, - - { - Name: "members", - Aliases: []string{"m"}, - Usage: "Get the oracle DAO members", - UsageText: "rocketpool api odao members", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getMembers(c)) - return nil - - }, - }, - - { - Name: "proposals", - Aliases: []string{"p"}, - Usage: "Get the oracle DAO proposals", - UsageText: "rocketpool api odao proposals", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getProposals(c)) - return nil - - }, - }, - - { - Name: "can-penalise-megapool", - Aliases: []string{"cpm"}, - Usage: "Checks whether we can penalise a megapool", - UsageText: "rocketpool api odao can-penalise-megapool megapool-address block amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - var err error - if err = cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - megapoolAddress, err := cliutils.ValidateAddress("megapool address", c.Args().Get(0)) - if err != nil { - return err - } - - block, err := cliutils.ValidateBigInt("block", c.Args().Get(1)) - if err != nil { - return err - } - - amount, err := cliutils.ValidateBigInt("amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canPenaliseMegapool(c, megapoolAddress, block, amount)) - return nil - - }, - }, - - { - Name: "penalise-megapool", - Aliases: []string{"pm"}, - Usage: "Penalise a megapool", - UsageText: "rocketpool api odao penalise-megapool megapool-address block amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - var err error - if err = cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - megapoolAddress, err := cliutils.ValidateAddress("megapool address", c.Args().Get(0)) - if err != nil { - return err - } - - block, err := cliutils.ValidateBigInt("block", c.Args().Get(1)) - if err != nil { - return err - } - - amount, err := cliutils.ValidateBigInt("amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(penaliseMegapool(c, megapoolAddress, block, amount)) - return nil - - }, - }, - - { - Name: "proposal-details", - Aliases: []string{"d"}, - Usage: "Get details of a proposal", - UsageText: "rocketpool api odao proposal-details proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - var err error - if err = cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - id, err := cliutils.ValidateUint("proposal-id", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getProposal(c, id)) - return nil - - }, - }, - - { - Name: "can-propose-invite", - Usage: "Check whether the node can propose inviting a new member", - UsageText: "rocketpool api odao can-propose-invite member-address member-id member-url", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - memberAddress, err := cliutils.ValidateAddress("member address", c.Args().Get(0)) - if err != nil { - return err - } - memberId, err := cliutils.ValidateDAOMemberID("member ID", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeInvite(c, memberAddress, memberId, c.Args().Get(2))) - return nil - - }, - }, - { - Name: "propose-invite", - Aliases: []string{"i"}, - Usage: "Propose inviting a new member", - UsageText: "rocketpool api odao propose-invite member-address member-id member-url", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - memberAddress, err := cliutils.ValidateAddress("member address", c.Args().Get(0)) - if err != nil { - return err - } - memberId, err := cliutils.ValidateDAOMemberID("member ID", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeInvite(c, memberAddress, memberId, c.Args().Get(2))) - return nil - - }, - }, - - { - Name: "can-propose-leave", - Usage: "Check whether the node can propose leaving the oracle DAO", - UsageText: "rocketpool api odao can-propose-leave", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canProposeLeave(c)) - return nil - - }, - }, - { - Name: "propose-leave", - Aliases: []string{"l"}, - Usage: "Propose leaving the oracle DAO", - UsageText: "rocketpool api odao propose-leave", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(proposeLeave(c)) - return nil - - }, - }, - - { - Name: "can-propose-kick", - Usage: "Check whether the node can propose kicking a member", - UsageText: "rocketpool api odao can-propose-kick member-address fine-amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - memberAddress, err := cliutils.ValidateAddress("member address", c.Args().Get(0)) - if err != nil { - return err - } - fineAmountWei, err := cliutils.ValidatePositiveOrZeroWeiAmount("fine amount", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeKick(c, memberAddress, fineAmountWei)) - return nil - - }, - }, - { - Name: "propose-kick", - Aliases: []string{"k"}, - Usage: "Propose kicking a member", - UsageText: "rocketpool api odao propose-kick member-address fine-amount", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - memberAddress, err := cliutils.ValidateAddress("member address", c.Args().Get(0)) - if err != nil { - return err - } - fineAmountWei, err := cliutils.ValidatePositiveOrZeroWeiAmount("fine amount", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeKick(c, memberAddress, fineAmountWei)) - return nil - - }, - }, - - { - Name: "can-cancel-proposal", - Usage: "Check whether the node can cancel a proposal", - UsageText: "rocketpool api odao can-cancel-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canCancelProposal(c, proposalId)) - return nil - - }, - }, - { - Name: "cancel-proposal", - Aliases: []string{"c"}, - Usage: "Cancel a proposal made by the node", - UsageText: "rocketpool api odao cancel-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(cancelProposal(c, proposalId)) - return nil - - }, - }, - - { - Name: "can-vote-proposal", - Usage: "Check whether the node can vote on a proposal", - UsageText: "rocketpool api odao can-vote-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canVoteOnProposal(c, proposalId)) - return nil - - }, - }, - { - Name: "vote-proposal", - Aliases: []string{"v"}, - Usage: "Vote on a proposal", - UsageText: "rocketpool api odao vote-proposal proposal-id support", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - support, err := cliutils.ValidateBool("support", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(voteOnProposal(c, proposalId, support)) - return nil - - }, - }, - - { - Name: "can-execute-proposal", - Usage: "Check whether the node can execute a proposal", - UsageText: "rocketpool api odao can-execute-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canExecuteProposal(c, proposalId)) - return nil - - }, - }, - { - Name: "execute-proposal", - Aliases: []string{"x"}, - Usage: "Execute a proposal", - UsageText: "rocketpool api odao execute-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(executeProposal(c, proposalId)) - return nil - - }, - }, - - { - Name: "can-join", - Usage: "Check whether the node can join the oracle DAO", - UsageText: "rocketpool api odao can-join", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canJoin(c)) - return nil - - }, - }, - { - Name: "join-approve-rpl", - Aliases: []string{"j1"}, - Usage: "Approves the RPL bond transfer prior to join the oracle DAO", - UsageText: "rocketpool api odao join-approve-rpl", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(approveRpl(c)) - return nil - - }, - }, - { - Name: "join", - Aliases: []string{"j2"}, - Usage: "Join the oracle DAO (requires an executed invite proposal)", - UsageText: "rocketpool api odao join tx-hash", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - hash, err := cliutils.ValidateTxHash("tx-hash", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(waitForApprovalAndJoin(c, hash)) - return nil - - }, - }, - - { - Name: "can-leave", - Usage: "Check whether the node can leave the oracle DAO", - UsageText: "rocketpool api odao can-leave", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canLeave(c)) - return nil - - }, - }, - { - Name: "leave", - Aliases: []string{"e"}, - Usage: "Leave the oracle DAO (requires an executed leave proposal)", - UsageText: "rocketpool api odao leave bond-refund-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - bondRefundAddress, err := cliutils.ValidateAddress("bond refund address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(leave(c, bondRefundAddress)) - return nil - - }, - }, - - { - Name: "can-propose-members-quorum", - Usage: "Check whether the node can propose the members.quorum setting", - UsageText: "rocketpool api odao can-propose-members-quorum value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - quorum, err := cliutils.ValidateFraction("quorum", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingMembersQuorum(c, quorum)) - return nil - - }, - }, - { - Name: "propose-members-quorum", - Usage: "Propose updating the members.quorum setting", - UsageText: "rocketpool api odao propose-members-quorum value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - quorum, err := cliutils.ValidateFraction("quorum", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingMembersQuorum(c, quorum)) - return nil - - }, - }, - - { - Name: "can-propose-members-rplbond", - Usage: "Check whether the node can propose the members.rplbond setting", - UsageText: "rocketpool api odao can-propose-members-rplbond value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - bondAmountWei, err := cliutils.ValidateWeiAmount("RPL bond amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingMembersRplBond(c, bondAmountWei)) - return nil - - }, - }, - { - Name: "propose-members-rplbond", - Usage: "Propose updating the members.rplbond setting", - UsageText: "rocketpool api odao propose-members-rplbond value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - bondAmountWei, err := cliutils.ValidateWeiAmount("RPL bond amount", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingMembersRplBond(c, bondAmountWei)) - return nil - - }, - }, - - { - Name: "can-propose-members-minipool-unbonded-max", - Usage: "Check whether the node can propose the members.minipool.unbonded.max setting", - UsageText: "rocketpool api odao can-propose-members-minipool-unbonded-max value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - unbondedMinipoolMax, err := cliutils.ValidateUint("maximum unbonded minipool count", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingMinipoolUnbondedMax(c, unbondedMinipoolMax)) - return nil - - }, - }, - { - Name: "propose-members-minipool-unbonded-max", - Usage: "Propose updating the members.minipool.unbonded.max setting", - UsageText: "rocketpool api odao propose-members-minipool-unbonded-max value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - unbondedMinipoolMax, err := cliutils.ValidateUint("maximum unbonded minipool count", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingMinipoolUnbondedMax(c, unbondedMinipoolMax)) - return nil - - }, - }, - - { - Name: "can-propose-proposal-cooldown", - Usage: "Check whether the node can propose the proposal.cooldown setting", - UsageText: "rocketpool api odao can-propose-proposal-cooldown value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalCooldownBlocks, err := cliutils.ValidateUint("proposal cooldown period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingProposalCooldown(c, proposalCooldownBlocks)) - return nil - - }, - }, - { - Name: "propose-proposal-cooldown", - Usage: "Propose updating the proposal.cooldown setting", - UsageText: "rocketpool api odao propose-proposal-cooldown value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalCooldownBlocks, err := cliutils.ValidateUint("proposal cooldown period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingProposalCooldown(c, proposalCooldownBlocks)) - return nil - - }, - }, - - { - Name: "can-propose-proposal-vote-timespan", - Usage: "Check whether the node can propose the proposal.vote.time setting", - UsageText: "rocketpool api odao can-propose-proposal-vote-timespan value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalVoteTimespan, err := cliutils.ValidateUint("proposal voting period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingProposalVoteTimespan(c, proposalVoteTimespan)) - return nil - - }, - }, - { - Name: "propose-proposal-vote-timespan", - Usage: "Propose updating the proposal.vote.time setting", - UsageText: "rocketpool api odao propose-proposal-vote-timespan value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalVoteTimespan, err := cliutils.ValidateUint("proposal voting period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingProposalVoteTimespan(c, proposalVoteTimespan)) - return nil - - }, - }, - - { - Name: "can-propose-proposal-vote-delay-timespan", - Usage: "Check whether the node can propose the proposal.vote.delay.time setting", - UsageText: "rocketpool api odao can-propose-proposal-vote-delay-timespan value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalDelayTimespan, err := cliutils.ValidateUint("proposal delay period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingProposalVoteDelayTimespan(c, proposalDelayTimespan)) - return nil - - }, - }, - { - Name: "propose-proposal-vote-delay-timespan", - Usage: "Propose updating the proposal.vote.delay.time setting", - UsageText: "rocketpool api odao propose-proposal-vote-delay-timespan value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalDelayTimespan, err := cliutils.ValidateUint("proposal delay period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingProposalVoteDelayTimespan(c, proposalDelayTimespan)) - return nil - - }, - }, - - { - Name: "can-propose-proposal-execute-timespan", - Usage: "Check whether the node can propose the proposal.execute.time setting", - UsageText: "rocketpool api odao can-propose-proposal-execute-timespan value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalExecuteTimespan, err := cliutils.ValidateUint("proposal execution period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingProposalExecuteTimespan(c, proposalExecuteTimespan)) - return nil - - }, - }, - { - Name: "propose-proposal-execute-timespan", - Usage: "Propose updating the proposal.execute.time setting", - UsageText: "rocketpool api odao propose-proposal-execute-timespan value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalExecuteTimespan, err := cliutils.ValidateUint("proposal execution period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingProposalExecuteTimespan(c, proposalExecuteTimespan)) - return nil - - }, - }, - - { - Name: "can-propose-proposal-action-timespan", - Usage: "Check whether the node can propose the proposal.action.time setting", - UsageText: "rocketpool api odao can-propose-proposal-action-timespan value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalActionTimespan, err := cliutils.ValidateUint("proposal action period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingProposalActionTimespan(c, proposalActionTimespan)) - return nil - - }, - }, - { - Name: "propose-proposal-action-timespan", - Usage: "Propose updating the proposal.action.time setting", - UsageText: "rocketpool api odao propose-proposal-action-timespan value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalActionTimespan, err := cliutils.ValidateUint("proposal action period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingProposalActionTimespan(c, proposalActionTimespan)) - return nil - - }, - }, - - { - Name: "can-propose-scrub-period", - Usage: "Check whether the node can propose the minipool.scrub.period setting", - UsageText: "rocketpool api odao can-propose-scrub-period value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - scrubPeriod, err := cliutils.ValidateUint("scrub period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingScrubPeriod(c, scrubPeriod)) - return nil - - }, - }, - { - Name: "propose-scrub-period", - Usage: "Propose updating the minipool.scrub.period setting", - UsageText: "rocketpool api odao propose-scrub-period value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - scrubPeriod, err := cliutils.ValidateUint("scrub period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingScrubPeriod(c, scrubPeriod)) - return nil - - }, - }, - - { - Name: "can-propose-promotion-scrub-period", - Usage: "Check whether the node can propose the minipool.promotion.scrub.period setting", - UsageText: "rocketpool api odao can-propose-promotion-scrub-period value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - scrubPeriod, err := cliutils.ValidateUint("promotion scrub period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingPromotionScrubPeriod(c, scrubPeriod)) - return nil - - }, - }, - { - Name: "propose-promotion-scrub-period", - Usage: "Propose updating the minipool.promotion.scrub.period setting", - UsageText: "rocketpool api odao propose-promotion-scrub-period value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - scrubPeriod, err := cliutils.ValidateUint("promotion scrub period", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingPromotionScrubPeriod(c, scrubPeriod)) - return nil - - }, - }, - - { - Name: "can-propose-scrub-penalty-enabled", - Usage: "Check whether the node can propose the minipool.scrub.penalty.enabled setting", - UsageText: "rocketpool api odao can-propose-scrub-penalty-enabled value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - enabled, err := cliutils.ValidateBool("scrub penalty enabled", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingScrubPenaltyEnabled(c, enabled)) - return nil - - }, - }, - { - Name: "propose-scrub-penalty-enabled", - Usage: "Propose updating the minipool.scrub.penalty.enabled setting", - UsageText: "rocketpool api odao propose-scrub-penalty-enabled value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - enabled, err := cliutils.ValidateBool("scrub penalty enabled", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingScrubPenaltyEnabled(c, enabled)) - return nil - - }, - }, - - { - Name: "can-propose-bond-reduction-window-start", - Usage: "Check whether the node can propose the minipool.bond.reduction.window.start setting", - UsageText: "rocketpool api odao can-propose-bond-reduction-window-start value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - windowStart, err := cliutils.ValidateUint("window start", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingBondReductionWindowStart(c, windowStart)) - return nil - - }, - }, - { - Name: "propose-bond-reduction-window-start", - Usage: "Propose updating the minipool.bond.reduction.window.start setting", - UsageText: "rocketpool api odao propose-bond-reduction-window-start value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - windowStart, err := cliutils.ValidateUint("window start", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingBondReductionWindowStart(c, windowStart)) - return nil - - }, - }, - - { - Name: "can-propose-bond-reduction-window-length", - Usage: "Check whether the node can propose the minipool.bond.reduction.window.length setting", - UsageText: "rocketpool api odao can-propose-bond-reduction-window-length value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - windowLength, err := cliutils.ValidateUint("window length", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeSettingBondReductionWindowLength(c, windowLength)) - return nil - - }, - }, - { - Name: "propose-bond-reduction-window-length", - Usage: "Propose updating the minipool.bond.reduction.window.length setting", - UsageText: "rocketpool api odao propose-bond-reduction-window-length value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - windowLength, err := cliutils.ValidateUint("window length", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSettingBondReductionWindowLength(c, windowLength)) - return nil - - }, - }, - - { - Name: "get-member-settings", - Usage: "Get the ODAO settings related to ODAO members", - UsageText: "rocketpool api odao get-member-settings", - Action: func(ctx context.Context, c *cli.Command) error { - - // Run - api.PrintResponse(getMemberSettings(c)) - return nil - - }, - }, - { - Name: "get-proposal-settings", - Usage: "Get the ODAO settings related to ODAO proposals", - UsageText: "rocketpool api odao get-proposal-settings", - Action: func(ctx context.Context, c *cli.Command) error { - - // Run - api.PrintResponse(getProposalSettings(c)) - return nil - - }, - }, - { - Name: "get-minipool-settings", - Usage: "Get the ODAO settings related to minipools", - UsageText: "rocketpool api odao get-minipool-settings", - Action: func(ctx context.Context, c *cli.Command) error { - - // Run - api.PrintResponse(getMinipoolSettings(c)) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/odao/execute-proposal.go b/rocketpool/api/odao/execute-proposal.go index db1278f81..14ac9d759 100644 --- a/rocketpool/api/odao/execute-proposal.go +++ b/rocketpool/api/odao/execute-proposal.go @@ -1,7 +1,7 @@ package odao import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao" "github.com/rocket-pool/smartnode/bindings/dao/trustednode" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canExecuteProposal(c *cli.Command, proposalId uint64) (*api.CanExecuteTNDAOProposalResponse, error) { @@ -20,13 +19,13 @@ func canExecuteProposal(c *cli.Command, proposalId uint64) (*api.CanExecuteTNDAO if err := services.RequireNodeWallet(c); err != nil { return nil, err } - if err := services.RequireRocketStorage(c); err != nil { - return nil, err - } w, err := services.GetWallet(c) if err != nil { return nil, err } + if err := services.RequireRocketStorage(c); err != nil { + return nil, err + } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -80,7 +79,7 @@ func canExecuteProposal(c *cli.Command, proposalId uint64) (*api.CanExecuteTNDAO } -func executeProposal(c *cli.Command, proposalId uint64) (*api.ExecuteTNDAOProposalResponse, error) { +func executeProposal(c *cli.Command, proposalId uint64, opts *bind.TransactOpts) (*api.ExecuteTNDAOProposalResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -89,10 +88,6 @@ func executeProposal(c *cli.Command, proposalId uint64) (*api.ExecuteTNDAOPropos if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -101,18 +96,6 @@ func executeProposal(c *cli.Command, proposalId uint64) (*api.ExecuteTNDAOPropos // Response response := api.ExecuteTNDAOProposalResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Cancel proposal hash, err := trustednode.ExecuteProposal(rp, proposalId, opts) if err != nil { diff --git a/rocketpool/api/odao/join.go b/rocketpool/api/odao/join.go index 996870fb9..f5ce226c9 100644 --- a/rocketpool/api/odao/join.go +++ b/rocketpool/api/odao/join.go @@ -1,9 +1,9 @@ package odao import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" tndao "github.com/rocket-pool/smartnode/bindings/dao/trustednode" tnsettings "github.com/rocket-pool/smartnode/bindings/settings/trustednode" @@ -14,7 +14,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canJoin(c *cli.Command) (*api.CanJoinTNDAOResponse, error) { @@ -118,16 +117,12 @@ func canJoin(c *cli.Command) (*api.CanJoinTNDAOResponse, error) { } -func approveRpl(c *cli.Command) (*api.JoinTNDAOApproveResponse, error) { +func approveRpl(c *cli.Command, opts *bind.TransactOpts) (*api.JoinTNDAOApproveResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -161,14 +156,6 @@ func approveRpl(c *cli.Command) (*api.JoinTNDAOApproveResponse, error) { } // Approve RPL allowance - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } hash, err := tokens.ApproveRPL(rp, *rocketDAONodeTrustedActionsAddress, rplBondAmount, opts) if err != nil { return nil, err @@ -181,16 +168,12 @@ func approveRpl(c *cli.Command) (*api.JoinTNDAOApproveResponse, error) { } -func waitForApprovalAndJoin(c *cli.Command, hash common.Hash) (*api.JoinTNDAOJoinResponse, error) { +func waitForApprovalAndJoin(c *cli.Command, hash common.Hash, opts *bind.TransactOpts) (*api.JoinTNDAOJoinResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -206,14 +189,6 @@ func waitForApprovalAndJoin(c *cli.Command, hash common.Hash) (*api.JoinTNDAOJoi response := api.JoinTNDAOJoinResponse{} // Join - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } joinHash, err := tndao.Join(rp, opts) if err != nil { return nil, err diff --git a/rocketpool/api/odao/leave.go b/rocketpool/api/odao/leave.go index 7b43a319b..868015609 100644 --- a/rocketpool/api/odao/leave.go +++ b/rocketpool/api/odao/leave.go @@ -1,8 +1,7 @@ package odao import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/trustednode" "github.com/urfave/cli/v3" @@ -10,7 +9,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canLeave(c *cli.Command) (*api.CanLeaveTNDAOResponse, error) { @@ -80,16 +78,12 @@ func canLeave(c *cli.Command) (*api.CanLeaveTNDAOResponse, error) { } -func leave(c *cli.Command, bondRefundAddress common.Address) (*api.LeaveTNDAOResponse, error) { +func leave(c *cli.Command, bondRefundAddress common.Address, opts *bind.TransactOpts) (*api.LeaveTNDAOResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -98,18 +92,6 @@ func leave(c *cli.Command, bondRefundAddress common.Address) (*api.LeaveTNDAORes // Response response := api.LeaveTNDAOResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Leave hash, err := trustednode.Leave(rp, bondRefundAddress, opts) if err != nil { diff --git a/rocketpool/api/odao/penalise-megapool.go b/rocketpool/api/odao/penalise-megapool.go index df02e3604..a066cf56f 100644 --- a/rocketpool/api/odao/penalise-megapool.go +++ b/rocketpool/api/odao/penalise-megapool.go @@ -1,16 +1,15 @@ package odao import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/megapool" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canPenaliseMegapool(c *cli.Command, megapoolAddress common.Address, block *big.Int, amount *big.Int) (*api.CanPenaliseMegapoolResponse, error) { @@ -46,6 +45,7 @@ func canPenaliseMegapool(c *cli.Command, megapoolAddress common.Address, block * if err != nil { return nil, err } + gasInfo, err := megapool.EstimatePenaliseGas(rp, megapoolAddress, block, amount, opts) if err != nil { return nil, err @@ -57,16 +57,12 @@ func canPenaliseMegapool(c *cli.Command, megapoolAddress common.Address, block * } -func penaliseMegapool(c *cli.Command, megapoolAddress common.Address, block *big.Int, amount *big.Int) (*api.PenaliseMegapoolResponse, error) { +func penaliseMegapool(c *cli.Command, megapoolAddress common.Address, block *big.Int, amount *big.Int, opts *bind.TransactOpts) (*api.PenaliseMegapoolResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -75,18 +71,6 @@ func penaliseMegapool(c *cli.Command, megapoolAddress common.Address, block *big // Response response := api.PenaliseMegapoolResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Repay debt hash, err := megapool.Penalise(rp, megapoolAddress, block, amount, opts) if err != nil { diff --git a/rocketpool/api/odao/propose-invite.go b/rocketpool/api/odao/propose-invite.go index 398afae5d..e1933f4ff 100644 --- a/rocketpool/api/odao/propose-invite.go +++ b/rocketpool/api/odao/propose-invite.go @@ -3,6 +3,7 @@ package odao import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/trustednode" "github.com/urfave/cli/v3" @@ -10,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canProposeInvite(c *cli.Command, memberAddress common.Address, memberId, memberUrl string) (*api.CanProposeTNDAOInviteResponse, error) { @@ -81,16 +81,12 @@ func canProposeInvite(c *cli.Command, memberAddress common.Address, memberId, me } -func proposeInvite(c *cli.Command, memberAddress common.Address, memberId, memberUrl string) (*api.ProposeTNDAOInviteResponse, error) { +func proposeInvite(c *cli.Command, memberAddress common.Address, memberId, memberUrl string, opts *bind.TransactOpts) (*api.ProposeTNDAOInviteResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -99,18 +95,6 @@ func proposeInvite(c *cli.Command, memberAddress common.Address, memberId, membe // Response response := api.ProposeTNDAOInviteResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal message := fmt.Sprintf("invite %s (%s)", memberId, memberUrl) proposalId, hash, err := trustednode.ProposeInviteMember(rp, message, memberAddress, memberId, memberUrl, opts) diff --git a/rocketpool/api/odao/propose-kick.go b/rocketpool/api/odao/propose-kick.go index 73d977d84..56ef6893f 100644 --- a/rocketpool/api/odao/propose-kick.go +++ b/rocketpool/api/odao/propose-kick.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/trustednode" "github.com/rocket-pool/smartnode/bindings/utils/eth" @@ -12,7 +13,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/rocket-pool/smartnode/shared/utils/math" ) @@ -92,16 +92,12 @@ func canProposeKick(c *cli.Command, memberAddress common.Address, fineAmountWei } -func proposeKick(c *cli.Command, memberAddress common.Address, fineAmountWei *big.Int) (*api.ProposeTNDAOKickResponse, error) { +func proposeKick(c *cli.Command, memberAddress common.Address, fineAmountWei *big.Int, opts *bind.TransactOpts) (*api.ProposeTNDAOKickResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -132,18 +128,6 @@ func proposeKick(c *cli.Command, memberAddress common.Address, fineAmountWei *bi return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal message := fmt.Sprintf("kick %s (%s) with %.6f RPL fine", memberId, memberUrl, math.RoundDown(eth.WeiToEth(fineAmountWei), 6)) proposalId, hash, err := trustednode.ProposeKickMember(rp, message, memberAddress, fineAmountWei, opts) diff --git a/rocketpool/api/odao/propose-leave.go b/rocketpool/api/odao/propose-leave.go index 758bc442d..bd9c51d48 100644 --- a/rocketpool/api/odao/propose-leave.go +++ b/rocketpool/api/odao/propose-leave.go @@ -3,13 +3,14 @@ package odao import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/rocket-pool/smartnode/bindings/dao/trustednode" "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canProposeLeave(c *cli.Command) (*api.CanProposeTNDAOLeaveResponse, error) { @@ -92,7 +93,7 @@ func canProposeLeave(c *cli.Command) (*api.CanProposeTNDAOLeaveResponse, error) } -func proposeLeave(c *cli.Command) (*api.ProposeTNDAOLeaveResponse, error) { +func proposeLeave(c *cli.Command, opts *bind.TransactOpts) (*api.ProposeTNDAOLeaveResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { @@ -138,18 +139,6 @@ func proposeLeave(c *cli.Command) (*api.ProposeTNDAOLeaveResponse, error) { return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal message := fmt.Sprintf("%s (%s) leaves", nodeMemberId, nodeMemberUrl) proposalId, hash, err := trustednode.ProposeMemberLeave(rp, message, nodeAccount.Address, opts) diff --git a/rocketpool/api/odao/propose-settings.go b/rocketpool/api/odao/propose-settings.go index 9d2c8b808..6a6479318 100644 --- a/rocketpool/api/odao/propose-settings.go +++ b/rocketpool/api/odao/propose-settings.go @@ -1,9 +1,10 @@ package odao import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/rocket-pool/smartnode/bindings/rocketpool" "github.com/rocket-pool/smartnode/bindings/settings/trustednode" "github.com/urfave/cli/v3" @@ -11,7 +12,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/services/wallet" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canProposeSetting(c *cli.Command, w wallet.Wallet, rp *rocketpool.RocketPool) (*api.CanProposeTNDAOSettingResponse, error) { @@ -63,6 +63,7 @@ func canProposeSettingMembersQuorum(c *cli.Command, quorum float64) (*api.CanPro if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeQuorumGas(rp, quorum, opts) if err != nil { return nil, err @@ -73,16 +74,12 @@ func canProposeSettingMembersQuorum(c *cli.Command, quorum float64) (*api.CanPro } -func proposeSettingMembersQuorum(c *cli.Command, quorum float64) (*api.ProposeTNDAOSettingMembersQuorumResponse, error) { +func proposeSettingMembersQuorum(c *cli.Command, quorum float64, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingMembersQuorumResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -91,18 +88,6 @@ func proposeSettingMembersQuorum(c *cli.Command, quorum float64) (*api.ProposeTN // Response response := api.ProposeTNDAOSettingMembersQuorumResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeQuorum(rp, quorum, opts) if err != nil { @@ -141,6 +126,7 @@ func canProposeSettingMembersRplBond(c *cli.Command, bondAmountWei *big.Int) (*a if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeRPLBondGas(rp, bondAmountWei, opts) if err != nil { return nil, err @@ -151,16 +137,12 @@ func canProposeSettingMembersRplBond(c *cli.Command, bondAmountWei *big.Int) (*a } -func proposeSettingMembersRplBond(c *cli.Command, bondAmountWei *big.Int) (*api.ProposeTNDAOSettingMembersRplBondResponse, error) { +func proposeSettingMembersRplBond(c *cli.Command, bondAmountWei *big.Int, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingMembersRplBondResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -169,18 +151,6 @@ func proposeSettingMembersRplBond(c *cli.Command, bondAmountWei *big.Int) (*api. // Response response := api.ProposeTNDAOSettingMembersRplBondResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeRPLBond(rp, bondAmountWei, opts) if err != nil { @@ -219,6 +189,7 @@ func canProposeSettingMinipoolUnbondedMax(c *cli.Command, unbondedMinipoolMax ui if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeMinipoolUnbondedMaxGas(rp, unbondedMinipoolMax, opts) if err != nil { return nil, err @@ -229,16 +200,12 @@ func canProposeSettingMinipoolUnbondedMax(c *cli.Command, unbondedMinipoolMax ui } -func proposeSettingMinipoolUnbondedMax(c *cli.Command, unbondedMinipoolMax uint64) (*api.ProposeTNDAOSettingMinipoolUnbondedMaxResponse, error) { +func proposeSettingMinipoolUnbondedMax(c *cli.Command, unbondedMinipoolMax uint64, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingMinipoolUnbondedMaxResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -247,18 +214,6 @@ func proposeSettingMinipoolUnbondedMax(c *cli.Command, unbondedMinipoolMax uint6 // Response response := api.ProposeTNDAOSettingMinipoolUnbondedMaxResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeMinipoolUnbondedMax(rp, unbondedMinipoolMax, opts) if err != nil { @@ -297,6 +252,7 @@ func canProposeSettingProposalCooldown(c *cli.Command, proposalCooldownTimespan if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeProposalCooldownTimeGas(rp, proposalCooldownTimespan, opts) if err != nil { return nil, err @@ -307,16 +263,12 @@ func canProposeSettingProposalCooldown(c *cli.Command, proposalCooldownTimespan } -func proposeSettingProposalCooldown(c *cli.Command, proposalCooldownTimespan uint64) (*api.ProposeTNDAOSettingProposalCooldownResponse, error) { +func proposeSettingProposalCooldown(c *cli.Command, proposalCooldownTimespan uint64, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingProposalCooldownResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -325,18 +277,6 @@ func proposeSettingProposalCooldown(c *cli.Command, proposalCooldownTimespan uin // Response response := api.ProposeTNDAOSettingProposalCooldownResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeProposalCooldownTime(rp, proposalCooldownTimespan, opts) if err != nil { @@ -375,6 +315,7 @@ func canProposeSettingProposalVoteTimespan(c *cli.Command, proposalVoteTimespan if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeProposalVoteTimeGas(rp, proposalVoteTimespan, opts) if err != nil { return nil, err @@ -385,16 +326,12 @@ func canProposeSettingProposalVoteTimespan(c *cli.Command, proposalVoteTimespan } -func proposeSettingProposalVoteTimespan(c *cli.Command, proposalVoteTimespan uint64) (*api.ProposeTNDAOSettingProposalVoteTimespanResponse, error) { +func proposeSettingProposalVoteTimespan(c *cli.Command, proposalVoteTimespan uint64, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingProposalVoteTimespanResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -403,18 +340,6 @@ func proposeSettingProposalVoteTimespan(c *cli.Command, proposalVoteTimespan uin // Response response := api.ProposeTNDAOSettingProposalVoteTimespanResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeProposalVoteTime(rp, proposalVoteTimespan, opts) if err != nil { @@ -453,6 +378,7 @@ func canProposeSettingProposalVoteDelayTimespan(c *cli.Command, proposalDelayTim if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeProposalVoteDelayTimeGas(rp, proposalDelayTimespan, opts) if err != nil { return nil, err @@ -463,16 +389,12 @@ func canProposeSettingProposalVoteDelayTimespan(c *cli.Command, proposalDelayTim } -func proposeSettingProposalVoteDelayTimespan(c *cli.Command, proposalDelayTimespan uint64) (*api.ProposeTNDAOSettingProposalVoteDelayTimespanResponse, error) { +func proposeSettingProposalVoteDelayTimespan(c *cli.Command, proposalDelayTimespan uint64, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingProposalVoteDelayTimespanResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -481,18 +403,6 @@ func proposeSettingProposalVoteDelayTimespan(c *cli.Command, proposalDelayTimesp // Response response := api.ProposeTNDAOSettingProposalVoteDelayTimespanResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeProposalVoteDelayTime(rp, proposalDelayTimespan, opts) if err != nil { @@ -531,6 +441,7 @@ func canProposeSettingProposalExecuteTimespan(c *cli.Command, proposalExecuteTim if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeProposalExecuteTimeGas(rp, proposalExecuteTimespan, opts) if err != nil { return nil, err @@ -541,16 +452,12 @@ func canProposeSettingProposalExecuteTimespan(c *cli.Command, proposalExecuteTim } -func proposeSettingProposalExecuteTimespan(c *cli.Command, proposalExecuteTimespan uint64) (*api.ProposeTNDAOSettingProposalExecuteTimespanResponse, error) { +func proposeSettingProposalExecuteTimespan(c *cli.Command, proposalExecuteTimespan uint64, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingProposalExecuteTimespanResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -559,18 +466,6 @@ func proposeSettingProposalExecuteTimespan(c *cli.Command, proposalExecuteTimesp // Response response := api.ProposeTNDAOSettingProposalExecuteTimespanResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeProposalExecuteTime(rp, proposalExecuteTimespan, opts) if err != nil { @@ -609,6 +504,7 @@ func canProposeSettingProposalActionTimespan(c *cli.Command, proposalActionTimes if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeProposalActionTimeGas(rp, proposalActionTimespan, opts) if err != nil { return nil, err @@ -619,16 +515,12 @@ func canProposeSettingProposalActionTimespan(c *cli.Command, proposalActionTimes } -func proposeSettingProposalActionTimespan(c *cli.Command, proposalActionTimespan uint64) (*api.ProposeTNDAOSettingProposalActionTimespanResponse, error) { +func proposeSettingProposalActionTimespan(c *cli.Command, proposalActionTimespan uint64, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingProposalActionTimespanResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -637,18 +529,6 @@ func proposeSettingProposalActionTimespan(c *cli.Command, proposalActionTimespan // Response response := api.ProposeTNDAOSettingProposalActionTimespanResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeProposalActionTime(rp, proposalActionTimespan, opts) if err != nil { @@ -687,6 +567,7 @@ func canProposeSettingScrubPeriod(c *cli.Command, scrubPeriod uint64) (*api.CanP if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeScrubPeriodGas(rp, scrubPeriod, opts) if err != nil { return nil, err @@ -697,16 +578,12 @@ func canProposeSettingScrubPeriod(c *cli.Command, scrubPeriod uint64) (*api.CanP } -func proposeSettingScrubPeriod(c *cli.Command, scrubPeriod uint64) (*api.ProposeTNDAOSettingScrubPeriodResponse, error) { +func proposeSettingScrubPeriod(c *cli.Command, scrubPeriod uint64, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingScrubPeriodResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -715,18 +592,6 @@ func proposeSettingScrubPeriod(c *cli.Command, scrubPeriod uint64) (*api.Propose // Response response := api.ProposeTNDAOSettingScrubPeriodResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeScrubPeriod(rp, scrubPeriod, opts) if err != nil { @@ -765,6 +630,7 @@ func canProposeSettingPromotionScrubPeriod(c *cli.Command, promotionScrubPeriod if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposePromotionScrubPeriodGas(rp, promotionScrubPeriod, opts) if err != nil { return nil, err @@ -775,16 +641,12 @@ func canProposeSettingPromotionScrubPeriod(c *cli.Command, promotionScrubPeriod } -func proposeSettingPromotionScrubPeriod(c *cli.Command, promotionScrubPeriod uint64) (*api.ProposeTNDAOSettingPromotionScrubPeriodResponse, error) { +func proposeSettingPromotionScrubPeriod(c *cli.Command, promotionScrubPeriod uint64, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingPromotionScrubPeriodResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -793,18 +655,6 @@ func proposeSettingPromotionScrubPeriod(c *cli.Command, promotionScrubPeriod uin // Response response := api.ProposeTNDAOSettingPromotionScrubPeriodResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposePromotionScrubPeriod(rp, promotionScrubPeriod, opts) if err != nil { @@ -843,6 +693,7 @@ func canProposeSettingScrubPenaltyEnabled(c *cli.Command, enabled bool) (*api.Ca if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeScrubPenaltyEnabledGas(rp, enabled, opts) if err != nil { return nil, err @@ -853,16 +704,12 @@ func canProposeSettingScrubPenaltyEnabled(c *cli.Command, enabled bool) (*api.Ca } -func proposeSettingScrubPenaltyEnabled(c *cli.Command, enabled bool) (*api.ProposeTNDAOSettingScrubPeriodResponse, error) { +func proposeSettingScrubPenaltyEnabled(c *cli.Command, enabled bool, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingScrubPeriodResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -871,18 +718,6 @@ func proposeSettingScrubPenaltyEnabled(c *cli.Command, enabled bool) (*api.Propo // Response response := api.ProposeTNDAOSettingScrubPeriodResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeScrubPenaltyEnabled(rp, enabled, opts) if err != nil { @@ -921,6 +756,7 @@ func canProposeSettingBondReductionWindowStart(c *cli.Command, bondReductionWind if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeBondReductionWindowStartGas(rp, bondReductionWindowStart, opts) if err != nil { return nil, err @@ -931,16 +767,12 @@ func canProposeSettingBondReductionWindowStart(c *cli.Command, bondReductionWind } -func proposeSettingBondReductionWindowStart(c *cli.Command, bondReductionWindowStart uint64) (*api.ProposeTNDAOSettingScrubPeriodResponse, error) { +func proposeSettingBondReductionWindowStart(c *cli.Command, bondReductionWindowStart uint64, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingScrubPeriodResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -949,18 +781,6 @@ func proposeSettingBondReductionWindowStart(c *cli.Command, bondReductionWindowS // Response response := api.ProposeTNDAOSettingScrubPeriodResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeBondReductionWindowStart(rp, bondReductionWindowStart, opts) if err != nil { @@ -999,6 +819,7 @@ func canProposeSettingBondReductionWindowLength(c *cli.Command, bondReductionWin if err != nil { return nil, err } + gasInfo, err := trustednode.EstimateProposeBondReductionWindowLengthGas(rp, bondReductionWindowLength, opts) if err != nil { return nil, err @@ -1009,16 +830,12 @@ func canProposeSettingBondReductionWindowLength(c *cli.Command, bondReductionWin } -func proposeSettingBondReductionWindowLength(c *cli.Command, bondReductionWindowLength uint64) (*api.ProposeTNDAOSettingScrubPeriodResponse, error) { +func proposeSettingBondReductionWindowLength(c *cli.Command, bondReductionWindowLength uint64, opts *bind.TransactOpts) (*api.ProposeTNDAOSettingScrubPeriodResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -1027,18 +844,6 @@ func proposeSettingBondReductionWindowLength(c *cli.Command, bondReductionWindow // Response response := api.ProposeTNDAOSettingScrubPeriodResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal proposalId, hash, err := trustednode.ProposeBondReductionWindowLength(rp, bondReductionWindowLength, opts) if err != nil { diff --git a/rocketpool/api/odao/routes.go b/rocketpool/api/odao/routes.go new file mode 100644 index 000000000..55de36b6b --- /dev/null +++ b/rocketpool/api/odao/routes.go @@ -0,0 +1,691 @@ +package odao + +import ( + "fmt" + "math/big" + "net/http" + "strconv" + + "github.com/ethereum/go-ethereum/common" + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/shared/services" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +// RegisterRoutes registers the odao module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/odao/status", func(w http.ResponseWriter, r *http.Request) { + resp, err := getStatus(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/members", func(w http.ResponseWriter, r *http.Request) { + resp, err := getMembers(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/proposals", func(w http.ResponseWriter, r *http.Request) { + resp, err := getProposals(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/proposal-details", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := getProposal(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-invite", func(w http.ResponseWriter, r *http.Request) { + addr, memberId, memberUrl, err := parseInviteParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeInvite(c, addr, memberId, memberUrl) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-invite", func(w http.ResponseWriter, r *http.Request) { + addr, memberId, memberUrl, err := parseInviteParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeInvite(c, addr, memberId, memberUrl, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-leave", func(w http.ResponseWriter, r *http.Request) { + resp, err := canProposeLeave(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-leave", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeLeave(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-kick", func(w http.ResponseWriter, r *http.Request) { + addr, fine, err := parseKickParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeKick(c, addr, fine) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-kick", func(w http.ResponseWriter, r *http.Request) { + addr, fine, err := parseKickParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeKick(c, addr, fine, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-cancel-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canCancelProposal(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/cancel-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := cancelProposal(c, id, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-vote-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canVoteOnProposal(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/vote-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + supportStr := r.FormValue("support") + support := supportStr == "true" + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := voteOnProposal(c, id, support, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-execute-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canExecuteProposal(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/execute-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := executeProposal(c, id, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-join", func(w http.ResponseWriter, r *http.Request) { + resp, err := canJoin(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/join-approve-rpl", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := approveRpl(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/join", func(w http.ResponseWriter, r *http.Request) { + hashStr := r.FormValue("approvalTxHash") + if hashStr == "" { + apiutils.WriteErrorResponse(w, fmt.Errorf("missing required parameter: approvalTxHash")) + return + } + hash := common.HexToHash(hashStr) + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := waitForApprovalAndJoin(c, hash, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-leave", func(w http.ResponseWriter, r *http.Request) { + resp, err := canLeave(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/leave", func(w http.ResponseWriter, r *http.Request) { + bondRefundStr := r.FormValue("bondRefundAddress") + if bondRefundStr == "" { + apiutils.WriteErrorResponse(w, fmt.Errorf("missing required parameter: bondRefundAddress")) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := leave(c, common.HexToAddress(bondRefundStr), opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/get-member-settings", func(w http.ResponseWriter, r *http.Request) { + resp, err := getMemberSettings(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/get-proposal-settings", func(w http.ResponseWriter, r *http.Request) { + resp, err := getProposalSettings(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/get-minipool-settings", func(w http.ResponseWriter, r *http.Request) { + resp, err := getMinipoolSettings(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-penalise-megapool", func(w http.ResponseWriter, r *http.Request) { + megapool, block, amount, err := parsePenaliseParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canPenaliseMegapool(c, megapool, block, amount) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/penalise-megapool", func(w http.ResponseWriter, r *http.Request) { + megapool, block, amount, err := parsePenaliseParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := penaliseMegapool(c, megapool, block, amount, opts) + apiutils.WriteResponse(w, resp, err) + }) + + // propose-settings endpoints + mux.HandleFunc("/api/odao/can-propose-members-quorum", func(w http.ResponseWriter, r *http.Request) { + quorum, err := parseFloat64(r, "quorum") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingMembersQuorum(c, quorum) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-members-quorum", func(w http.ResponseWriter, r *http.Request) { + quorum, err := parseFloat64(r, "quorum") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingMembersQuorum(c, quorum, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-members-rplbond", func(w http.ResponseWriter, r *http.Request) { + bond, err := parseBigInt(r, "bondAmountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingMembersRplBond(c, bond) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-members-rplbond", func(w http.ResponseWriter, r *http.Request) { + bond, err := parseBigInt(r, "bondAmountWei") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingMembersRplBond(c, bond, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-members-minipool-unbonded-max", func(w http.ResponseWriter, r *http.Request) { + max, err := parseUint64(r, "max") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingMinipoolUnbondedMax(c, max) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-members-minipool-unbonded-max", func(w http.ResponseWriter, r *http.Request) { + max, err := parseUint64(r, "max") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingMinipoolUnbondedMax(c, max, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-proposal-cooldown", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingProposalCooldown(c, val) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-proposal-cooldown", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingProposalCooldown(c, val, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-proposal-vote-timespan", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingProposalVoteTimespan(c, val) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-proposal-vote-timespan", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingProposalVoteTimespan(c, val, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-proposal-vote-delay-timespan", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingProposalVoteDelayTimespan(c, val) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-proposal-vote-delay-timespan", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingProposalVoteDelayTimespan(c, val, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-proposal-execute-timespan", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingProposalExecuteTimespan(c, val) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-proposal-execute-timespan", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingProposalExecuteTimespan(c, val, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-proposal-action-timespan", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingProposalActionTimespan(c, val) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-proposal-action-timespan", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingProposalActionTimespan(c, val, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-scrub-period", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingScrubPeriod(c, val) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-scrub-period", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingScrubPeriod(c, val, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-promotion-scrub-period", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingPromotionScrubPeriod(c, val) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-promotion-scrub-period", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingPromotionScrubPeriod(c, val, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-scrub-penalty-enabled", func(w http.ResponseWriter, r *http.Request) { + enabledStr := r.URL.Query().Get("enabled") + resp, err := canProposeSettingScrubPenaltyEnabled(c, enabledStr == "true") + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-scrub-penalty-enabled", func(w http.ResponseWriter, r *http.Request) { + enabledStr := r.FormValue("enabled") + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingScrubPenaltyEnabled(c, enabledStr == "true", opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-bond-reduction-window-start", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingBondReductionWindowStart(c, val) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-bond-reduction-window-start", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingBondReductionWindowStart(c, val, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/can-propose-bond-reduction-window-length", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeSettingBondReductionWindowLength(c, val) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/odao/propose-bond-reduction-window-length", func(w http.ResponseWriter, r *http.Request) { + val, err := parseUint64(r, "value") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSettingBondReductionWindowLength(c, val, opts) + apiutils.WriteResponse(w, resp, err) + }) +} + +func parseUint64(r *http.Request, name string) (uint64, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + val, err := strconv.ParseUint(raw, 10, 64) + if err != nil { + return 0, fmt.Errorf("invalid %s: %s", name, raw) + } + return val, nil +} + +func parseFloat64(r *http.Request, name string) (float64, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + val, err := strconv.ParseFloat(raw, 64) + if err != nil { + return 0, fmt.Errorf("invalid %s: %s", name, raw) + } + return val, nil +} + +func parseBigInt(r *http.Request, name string) (*big.Int, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + val, ok := new(big.Int).SetString(raw, 10) + if !ok { + return nil, fmt.Errorf("invalid %s: %s", name, raw) + } + return val, nil +} + +func parseInviteParams(r *http.Request) (common.Address, string, string, error) { + addrStr := r.URL.Query().Get("address") + if addrStr == "" { + addrStr = r.FormValue("address") + } + if addrStr == "" { + return common.Address{}, "", "", fmt.Errorf("missing required parameter: address") + } + memberId := r.URL.Query().Get("memberId") + if memberId == "" { + memberId = r.FormValue("memberId") + } + memberUrl := r.URL.Query().Get("memberUrl") + if memberUrl == "" { + memberUrl = r.FormValue("memberUrl") + } + return common.HexToAddress(addrStr), memberId, memberUrl, nil +} + +func parseKickParams(r *http.Request) (common.Address, *big.Int, error) { + addrStr := r.URL.Query().Get("address") + if addrStr == "" { + addrStr = r.FormValue("address") + } + if addrStr == "" { + return common.Address{}, nil, fmt.Errorf("missing required parameter: address") + } + fineStr := r.URL.Query().Get("fineAmountWei") + if fineStr == "" { + fineStr = r.FormValue("fineAmountWei") + } + fine, ok := new(big.Int).SetString(fineStr, 10) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid fineAmountWei: %s", fineStr) + } + return common.HexToAddress(addrStr), fine, nil +} + +func parsePenaliseParams(r *http.Request) (common.Address, *big.Int, *big.Int, error) { + addrStr := r.URL.Query().Get("megapoolAddress") + if addrStr == "" { + addrStr = r.FormValue("megapoolAddress") + } + blockStr := r.URL.Query().Get("block") + if blockStr == "" { + blockStr = r.FormValue("block") + } + amountStr := r.URL.Query().Get("amountWei") + if amountStr == "" { + amountStr = r.FormValue("amountWei") + } + block, ok := new(big.Int).SetString(blockStr, 10) + if !ok { + return common.Address{}, nil, nil, fmt.Errorf("invalid block: %s", blockStr) + } + amount, ok := new(big.Int).SetString(amountStr, 10) + if !ok { + return common.Address{}, nil, nil, fmt.Errorf("invalid amountWei: %s", amountStr) + } + return common.HexToAddress(addrStr), block, amount, nil +} diff --git a/rocketpool/api/odao/vote-proposal.go b/rocketpool/api/odao/vote-proposal.go index b22b06579..e2860fe2d 100644 --- a/rocketpool/api/odao/vote-proposal.go +++ b/rocketpool/api/odao/vote-proposal.go @@ -1,7 +1,7 @@ package odao import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao" "github.com/rocket-pool/smartnode/bindings/dao/trustednode" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canVoteOnProposal(c *cli.Command, proposalId uint64) (*api.CanVoteOnTNDAOProposalResponse, error) { @@ -111,16 +110,12 @@ func canVoteOnProposal(c *cli.Command, proposalId uint64) (*api.CanVoteOnTNDAOPr } -func voteOnProposal(c *cli.Command, proposalId uint64, support bool) (*api.VoteOnTNDAOProposalResponse, error) { +func voteOnProposal(c *cli.Command, proposalId uint64, support bool, opts *bind.TransactOpts) (*api.VoteOnTNDAOProposalResponse, error) { // Get services if err := services.RequireNodeTrusted(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -129,18 +124,6 @@ func voteOnProposal(c *cli.Command, proposalId uint64, support bool) (*api.VoteO // Response response := api.VoteOnTNDAOProposalResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Vote on proposal hash, err := trustednode.VoteOnProposal(rp, proposalId, support, opts) if err != nil { diff --git a/rocketpool/api/pdao/claim-bonds.go b/rocketpool/api/pdao/claim-bonds.go index 228450038..a71015808 100644 --- a/rocketpool/api/pdao/claim-bonds.go +++ b/rocketpool/api/pdao/claim-bonds.go @@ -1,7 +1,7 @@ package pdao import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/rocketpool" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canClaimBonds(c *cli.Command, proposalId uint64, indices []uint64) (*api.PDAOCanClaimBondsResponse, error) { @@ -104,7 +103,7 @@ func canClaimBonds(c *cli.Command, proposalId uint64, indices []uint64) (*api.PD return &response, nil } -func claimBonds(c *cli.Command, isProposer bool, proposalId uint64, indices []uint64) (*api.PDAOClaimBondsResponse, error) { +func claimBonds(c *cli.Command, isProposer bool, proposalId uint64, indices []uint64, opts *bind.TransactOpts) (*api.PDAOClaimBondsResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { return nil, err @@ -112,10 +111,6 @@ func claimBonds(c *cli.Command, isProposer bool, proposalId uint64, indices []ui if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -124,18 +119,6 @@ func claimBonds(c *cli.Command, isProposer bool, proposalId uint64, indices []ui // Response response := api.PDAOClaimBondsResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Claim bonds if isProposer { response.TxHash, err = protocol.ClaimBondProposer(rp, proposalId, indices, opts) diff --git a/rocketpool/api/pdao/commands.go b/rocketpool/api/pdao/commands.go deleted file mode 100644 index ae5fc273d..000000000 --- a/rocketpool/api/pdao/commands.go +++ /dev/null @@ -1,1152 +0,0 @@ -package pdao - -import ( - "context" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage the Rocket Pool protocol DAO", - Commands: []*cli.Command{ - - { - Name: "proposals", - Aliases: []string{"p"}, - Usage: "Get the protocol DAO proposals", - UsageText: "rocketpool api pdao proposals", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getProposals(c)) - return nil - - }, - }, - - { - Name: "proposal-details", - Aliases: []string{"d"}, - Usage: "Get details of a proposal", - UsageText: "rocketpool api pdao proposal-details proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - var err error - if err = cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - id, err := cliutils.ValidateUint("proposal-id", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getProposal(c, id)) - return nil - - }, - }, - - { - Name: "can-vote-proposal", - Usage: "Check whether the node can vote on a proposal", - UsageText: "rocketpool api pdao can-vote-proposal proposal-id vote-direction", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - voteDir, err := cliutils.ValidateVoteDirection("vote direction", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canVoteOnProposal(c, proposalId, voteDir)) - return nil - - }, - }, - { - Name: "vote-proposal", - Aliases: []string{"v"}, - Usage: "Vote on a proposal", - UsageText: "rocketpool api pdao vote-proposal proposal-id vote-direction", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - voteDir, err := cliutils.ValidateVoteDirection("vote direction", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(voteOnProposal(c, proposalId, voteDir)) - return nil - - }, - }, - - { - Name: "can-override-vote", - Usage: "Check whether the node can override their delegate's vote on a proposal", - UsageText: "rocketpool api pdao can-override-vote proposal-id vote-direction", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - voteDir, err := cliutils.ValidateVoteDirection("vote direction", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canOverrideVote(c, proposalId, voteDir)) - return nil - - }, - }, - { - Name: "override-vote", - Usage: "Override the vote of the node's delegate on a proposal", - UsageText: "rocketpool api pdao override-vote proposal-id vote-direction", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - voteDir, err := cliutils.ValidateVoteDirection("vote direction", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(overrideVote(c, proposalId, voteDir)) - return nil - - }, - }, - - { - Name: "can-execute-proposal", - Usage: "Check whether the node can execute a proposal", - UsageText: "rocketpool api pdao can-execute-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canExecuteProposal(c, proposalId)) - return nil - - }, - }, - { - Name: "execute-proposal", - Aliases: []string{"x"}, - Usage: "Execute a proposal", - UsageText: "rocketpool api pdao execute-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(executeProposal(c, proposalId)) - return nil - - }, - }, - - { - Name: "get-settings", - Usage: "Get the Protocol DAO settings", - UsageText: "rocketpool api pdao get-member-settings", - Action: func(ctx context.Context, c *cli.Command) error { - - // Run - api.PrintResponse(getSettings(c)) - return nil - - }, - }, - - { - Name: "can-propose-setting", - Usage: "Check whether the node can propose a PDAO setting", - UsageText: "rocketpool api pdao can-propose-setting contract-name setting-name value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - contractName := c.Args().Get(0) - settingName := c.Args().Get(1) - value := c.Args().Get(2) - - // Run - api.PrintResponse(canProposeSetting(c, contractName, settingName, value)) - return nil - - }, - }, - { - Name: "propose-setting", - Usage: "Propose updating a PDAO setting (use can-propose-setting to get the pollard)", - UsageText: "rocketpool api pdao propose-setting contract-name setting-name value block-number", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 4); err != nil { - return err - } - contractName := c.Args().Get(0) - settingName := c.Args().Get(1) - value := c.Args().Get(2) - blockNumber, err := cliutils.ValidatePositiveUint32("block-number", c.Args().Get(3)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeSetting(c, contractName, settingName, value, blockNumber)) - return nil - - }, - }, - - { - Name: "get-rewards-percentages", - Usage: "Get the allocation percentages of RPL rewards for the Oracle DAO, the Protocol DAO, and the node operators", - UsageText: "rocketpool api pdao get-rewards-percentages", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getRewardsPercentages(c)) - return nil - - }, - }, - { - Name: "can-propose-rewards-percentages", - Usage: "Check whether the node can propose new RPL rewards allocation percentages for the Oracle DAO, the Protocol DAO, and the node operators", - UsageText: "rocketpool api pdao can-propose-rewards-percentages node odao pdao", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - node, err := cliutils.ValidateBigInt("node", c.Args().Get(0)) - if err != nil { - return err - } - odao, err := cliutils.ValidateBigInt("odao", c.Args().Get(1)) - if err != nil { - return err - } - pdao, err := cliutils.ValidateBigInt("pdao", c.Args().Get(2)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeRewardsPercentages(c, node, odao, pdao)) - return nil - - }, - }, - { - Name: "propose-rewards-percentages", - Usage: "Propose new RPL rewards allocation percentages for the Oracle DAO, the Protocol DAO, and the node operators", - UsageText: "rocketpool api pdao propose-rewards-percentages node odao pdao block-number", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 4); err != nil { - return err - } - node, err := cliutils.ValidateBigInt("node", c.Args().Get(0)) - if err != nil { - return err - } - odao, err := cliutils.ValidateBigInt("odao", c.Args().Get(1)) - if err != nil { - return err - } - pdao, err := cliutils.ValidateBigInt("pdao", c.Args().Get(2)) - if err != nil { - return err - } - blockNumber, err := cliutils.ValidateUint32("blockNumber", c.Args().Get(3)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeRewardsPercentages(c, node, odao, pdao, blockNumber)) - return nil - - }, - }, - - { - Name: "can-propose-one-time-spend", - Usage: "Check whether the node can propose a one-time spend of the Protocol DAO's treasury", - UsageText: "rocketpool api pdao can-propose-one-time-spend invoice-id recipient amount custom-message", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 4); err != nil { - return err - } - invoiceID := c.Args().Get(0) - recipient, err := cliutils.ValidateAddress("recipient", c.Args().Get(1)) - if err != nil { - return err - } - amount, err := cliutils.ValidateBigInt("amount", c.Args().Get(2)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeOneTimeSpend(c, invoiceID, recipient, amount, c.Args().Get(3))) - return nil - - }, - }, - { - Name: "propose-one-time-spend", - Usage: "Propose a one-time spend of the Protocol DAO's treasury", - UsageText: "rocketpool api pdao propose-one-time-spend invoice-id recipient amount block-number custom-message", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 5); err != nil { - return err - } - invoiceID := c.Args().Get(0) - recipient, err := cliutils.ValidateAddress("recipient", c.Args().Get(1)) - if err != nil { - return err - } - amount, err := cliutils.ValidateBigInt("amount", c.Args().Get(2)) - if err != nil { - return err - } - blockNumber, err := cliutils.ValidateUint32("blockNumber", c.Args().Get(3)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeOneTimeSpend(c, invoiceID, recipient, amount, blockNumber, c.Args().Get(4))) - return nil - - }, - }, - - { - Name: "can-propose-recurring-spend", - Usage: "Check whether the node can propose a recurring spend of the Protocol DAO's treasury", - UsageText: "rocketpool api pdao can-propose-recurring-spend contract-name recipient amount-per-period period-length start-time number-of-periods custom-message", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 7); err != nil { - return err - } - contractName := c.Args().Get(0) - recipient, err := cliutils.ValidateAddress("recipient", c.Args().Get(1)) - if err != nil { - return err - } - amountPerPeriod, err := cliutils.ValidateBigInt("amount-per-period", c.Args().Get(2)) - if err != nil { - return err - } - periodLength, err := cliutils.ValidateDuration("period-length", c.Args().Get(3)) - if err != nil { - return err - } - startTime, err := cliutils.ValidatePositiveUint("start-time", c.Args().Get(4)) - if err != nil { - return err - } - numberOfPeriods, err := cliutils.ValidatePositiveUint("number-of-periods", c.Args().Get(5)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeRecurringSpend(c, contractName, recipient, amountPerPeriod, periodLength, time.Unix(int64(startTime), 0), numberOfPeriods, c.Args().Get(6))) - return nil - - }, - }, - { - Name: "propose-recurring-spend", - Usage: "Propose a recurring spend of the Protocol DAO's treasury", - UsageText: "rocketpool api pdao propose-recurring-spend contract-name recipient amount-per-period period-length start-time number-of-periods block-number custom-message", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 8); err != nil { - return err - } - contractName := c.Args().Get(0) - recipient, err := cliutils.ValidateAddress("recipient", c.Args().Get(1)) - if err != nil { - return err - } - amountPerPeriod, err := cliutils.ValidateBigInt("amount-per-period", c.Args().Get(2)) - if err != nil { - return err - } - periodLength, err := cliutils.ValidateDuration("period-length", c.Args().Get(3)) - if err != nil { - return err - } - startTime, err := cliutils.ValidatePositiveUint("start-time", c.Args().Get(4)) - if err != nil { - return err - } - numberOfPeriods, err := cliutils.ValidatePositiveUint("number-of-periods", c.Args().Get(5)) - if err != nil { - return err - } - blockNumber, err := cliutils.ValidateUint32("blockNumber", c.Args().Get(6)) - if err != nil { - return err - } - // Run - api.PrintResponse(proposeRecurringSpend(c, contractName, recipient, amountPerPeriod, periodLength, time.Unix(int64(startTime), 0), numberOfPeriods, blockNumber, c.Args().Get(7))) - return nil - - }, - }, - - { - Name: "can-propose-recurring-spend-update", - Usage: "Check whether the node can propose an update to an existing recurring spend plan", - UsageText: "rocketpool api pdao can-propose-recurring-spend-update contract-name recipient amount-per-period period-length number-of-periods custom-message", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 6); err != nil { - return err - } - contractName := c.Args().Get(0) - recipient, err := cliutils.ValidateAddress("recipient", c.Args().Get(1)) - if err != nil { - return err - } - amountPerPeriod, err := cliutils.ValidateBigInt("amount-per-period", c.Args().Get(2)) - if err != nil { - return err - } - periodLength, err := cliutils.ValidateDuration("period-length", c.Args().Get(3)) - if err != nil { - return err - } - numberOfPeriods, err := cliutils.ValidatePositiveUint("number-of-periods", c.Args().Get(4)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeRecurringSpendUpdate(c, contractName, recipient, amountPerPeriod, periodLength, numberOfPeriods, c.Args().Get(5))) - return nil - - }, - }, - { - Name: "propose-recurring-spend-update", - Usage: "Propose an update to an existing recurring spend plan", - UsageText: "rocketpool api pdao propose-recurring-spend-update contract-name recipient amount-per-period period-length number-of-periods block-number custom-message", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 7); err != nil { - return err - } - contractName := c.Args().Get(0) - recipient, err := cliutils.ValidateAddress("recipient", c.Args().Get(1)) - if err != nil { - return err - } - amountPerPeriod, err := cliutils.ValidateBigInt("amount-per-period", c.Args().Get(2)) - if err != nil { - return err - } - periodLength, err := cliutils.ValidateDuration("period-length", c.Args().Get(3)) - if err != nil { - return err - } - numberOfPeriods, err := cliutils.ValidatePositiveUint("number-of-periods", c.Args().Get(4)) - if err != nil { - return err - } - blockNumber, err := cliutils.ValidateUint32("blockNumber", c.Args().Get(5)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeRecurringSpendUpdate(c, contractName, recipient, amountPerPeriod, periodLength, numberOfPeriods, blockNumber, c.Args().Get(6))) - return nil - - }, - }, - - { - Name: "can-propose-invite-to-security-council", - Usage: "Check whether the node can invite someone to the security council", - UsageText: "rocketpool api pdao can-propose-invite-to-security-council id address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - id := c.Args().Get(0) - address, err := cliutils.ValidateAddress("address", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeInviteToSecurityCouncil(c, id, address)) - return nil - - }, - }, - { - Name: "propose-invite-to-security-council", - Usage: "Propose inviting someone to the security council", - UsageText: "rocketpool api pdao propose-invite-to-security-council id address block-number", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - id := c.Args().Get(0) - address, err := cliutils.ValidateAddress("address", c.Args().Get(1)) - if err != nil { - return err - } - blockNumber, err := cliutils.ValidateUint32("blockNumber", c.Args().Get(2)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeInviteToSecurityCouncil(c, id, address, blockNumber)) - return nil - - }, - }, - - { - Name: "can-propose-kick-from-security-council", - Usage: "Check whether the node can kick someone from the security council", - UsageText: "rocketpool api pdao can-propose-kick-from-security-council address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - address, err := cliutils.ValidateAddress("address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeKickFromSecurityCouncil(c, address)) - return nil - - }, - }, - { - Name: "propose-kick-from-security-council", - Usage: "Propose kicking someone from the security council", - UsageText: "rocketpool api pdao propose-kick-from-security-council address block-number", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - address, err := cliutils.ValidateAddress("address", c.Args().Get(0)) - if err != nil { - return err - } - blockNumber, err := cliutils.ValidateUint32("blockNumber", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeKickFromSecurityCouncil(c, address, blockNumber)) - return nil - - }, - }, - - { - Name: "can-propose-kick-multi-from-security-council", - Usage: "Check whether the node can kick multiple members from the security council", - UsageText: "rocketpool api pdao can-propose-kick-multi-from-security-council addresses", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - addresses, err := cliutils.ValidateAddresses("address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeKickMultiFromSecurityCouncil(c, addresses)) - return nil - - }, - }, - { - Name: "propose-kick-multi-from-security-council", - Usage: "Propose kicking multiple members from the security council", - UsageText: "rocketpool api pdao propose-kick-multi-from-security-council addresses block-number", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - addresses, err := cliutils.ValidateAddresses("addresses", c.Args().Get(0)) - if err != nil { - return err - } - blockNumber, err := cliutils.ValidateUint32("blockNumber", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeKickMultiFromSecurityCouncil(c, addresses, blockNumber)) - return nil - - }, - }, - - { - Name: "can-propose-replace-member-of-security-council", - Usage: "Check whether the node can propose replacing someone on the security council with another member", - UsageText: "rocketpool api pdao can-propose-replace-member-of-security-council existing-address new-id new-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - existingAddress, err := cliutils.ValidateAddress("existingAddress", c.Args().Get(0)) - if err != nil { - return err - } - newID := c.Args().Get(1) - newAddress, err := cliutils.ValidateAddress("newAddress", c.Args().Get(2)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProposeReplaceMemberOfSecurityCouncil(c, existingAddress, newID, newAddress)) - return nil - - }, - }, - { - Name: "propose-replace-member-of-security-council", - Usage: "Propose replacing someone on the security council with another member", - UsageText: "rocketpool api pdao propose-replace-member-of-security-council existing-address new-id new-address block-number", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 4); err != nil { - return err - } - existingAddress, err := cliutils.ValidateAddress("existingAddress", c.Args().Get(0)) - if err != nil { - return err - } - newID := c.Args().Get(1) - newAddress, err := cliutils.ValidateAddress("newAddress", c.Args().Get(2)) - if err != nil { - return err - } - blockNumber, err := cliutils.ValidateUint32("blockNumber", c.Args().Get(3)) - if err != nil { - return err - } - - // Run - api.PrintResponse(proposeReplaceMemberOfSecurityCouncil(c, existingAddress, newID, newAddress, blockNumber)) - return nil - - }, - }, - - { - Name: "get-claimable-bonds", - Usage: "Get the list of proposals with claimable / rewardable bonds, and the relevant indices for each one", - UsageText: "rocketpool api pdao get-claimable-bonds", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getClaimableBonds(c)) - return nil - - }, - }, - - { - Name: "can-claim-bonds", - Usage: "Check whether the node can claim the bonds and/or rewards from a proposal", - UsageText: "rocketpool api pdao can-claim-bonds proposal-id tree-node-indices", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - indices, err := cliutils.ValidatePositiveUints("indices", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canClaimBonds(c, proposalId, indices)) - return nil - - }, - }, - { - Name: "claim-bonds", - Usage: "Claim the bonds and/or rewards from a proposal", - UsageText: "rocketpool api pdao claim-bonds is-proposer proposal-id tree-node-indice", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - isProposer, err := cliutils.ValidateBool("is-proposer", c.Args().Get(0)) - if err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal-id", c.Args().Get(1)) - if err != nil { - return err - } - indices, err := cliutils.ValidatePositiveUints("indices", c.Args().Get(2)) - if err != nil { - return err - } - - // Run - api.PrintResponse(claimBonds(c, isProposer, proposalId, indices)) - return nil - - }, - }, - - { - Name: "can-defeat-proposal", - Usage: "Check whether a proposal can be defeated with the provided tree index", - UsageText: "rocketpool api pdao can-defeat-proposal proposal-id challenged-index", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal-id", c.Args().Get(0)) - if err != nil { - return err - } - index, err := cliutils.ValidatePositiveUint("challenged-index", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canDefeatProposal(c, proposalId, index)) - return nil - - }, - }, - { - Name: "defeat-proposal", - Usage: "Defeat a proposal if it still has a challenge after voting has started", - UsageText: "rocketpool api pdao defeat-proposal proposal-id challenged-index", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal-id", c.Args().Get(0)) - if err != nil { - return err - } - index, err := cliutils.ValidatePositiveUint("challenged-index", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(defeatProposal(c, proposalId, index)) - return nil - - }, - }, - - { - Name: "can-finalize-proposal", - Usage: "Check whether a proposal can be finalized after being vetoed", - UsageText: "rocketpool api pdao can-finalize-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal-id", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canFinalizeProposal(c, proposalId)) - return nil - - }, - }, - { - Name: "finalize-proposal", - Usage: "Finalize a proposal if it's been vetoed by burning the proposer's bond", - UsageText: "rocketpool api pdao finalize-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal-id", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(finalizeProposal(c, proposalId)) - return nil - - }, - }, - { - Name: "estimate-set-voting-delegate-gas", - Usage: "Estimate the gas required to set an on-chain voting delegate", - UsageText: "rocketpool api pdao estimate-set-voting-delegate-gas address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - delegate, err := cliutils.ValidateAddress("delegate", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(estimateSetVotingDelegateGas(c, delegate)) - return nil - - }, - }, - { - Name: "set-voting-delegate", - Usage: "Set an on-chain voting delegate for the node", - UsageText: "rocketpool api pdao set-voting-delegate address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - delegate, err := cliutils.ValidateAddress("delegate", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(setVotingDelegate(c, delegate)) - return nil - - }, - }, - { - Name: "get-current-voting-delegate", - Usage: "Get the current on-chain voting delegate for the node", - UsageText: "rocketpool api pdao get-current-voting-delegate", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getCurrentVotingDelegate(c)) - return nil - - }, - }, - { - Name: "status", - Usage: "Get the pdao status", - UsageText: "rocketpool api pdao status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getStatus(c)) - return nil - - }, - }, - { - Name: "can-set-signalling-address", - Usage: "Checks if signalling address can be set.", - UsageText: "rocketpool api pdao can-set-signalling-address signalling-address signature", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - signallingAddress, err := cliutils.ValidateAddress("signalling-address", c.Args().Get(0)) - if err != nil { - return err - } - signature, err := cliutils.ValidateSignature("signature", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canSetSignallingAddress(c, signallingAddress, signature)) - return nil - - }, - }, - { - Name: "set-signalling-address", - Usage: "Set the signalling address for the node", - UsageText: "rocketpool api pdao set-signalling-address signalling-address signature", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - signallingAddress, err := cliutils.ValidateAddress("signalling-address", c.Args().Get(0)) - if err != nil { - return err - } - signature, err := cliutils.ValidateSignature("signature", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(setSignallingAddress(c, signallingAddress, signature)) - return nil - - }, - }, - { - Name: "can-clear-signalling-address", - Usage: "Checks if the signalling address can be cleared.", - UsageText: "rocketpool api pdao can-clear-signalling-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - // Run - api.PrintResponse(canClearSignallingAddress(c)) - return nil - - }, - }, - { - Name: "clear-signalling-address", - Usage: "Clear the signalling delegate address for the node", - UsageText: "rocketpool api pdao clear-signalling-address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - // Run - api.PrintResponse(clearSignallingAddress(c)) - return nil - - }, - }, - { - Name: "can-propose-allow-listed-controllers", - Usage: "Check whether the node can propose a list of addresses that can update commission share parameters", - UsageText: "rocketpool api pdao can-propose-allow-listed-controllers addresses", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if c.NArg() > 2 { - return fmt.Errorf("Incorrect argument count;") - } - - var addressList []common.Address - var err error - if c.NArg() != 0 { - addressList, err = cliutils.ValidateAddresses("addressList", c.Args().Get(0)) - if err != nil { - return err - } - } - // Run - api.PrintResponse(canProposeAllowListedControllers(c, addressList)) - return nil - - }, - }, - { - Name: "propose-allow-listed-controllers", - Usage: "Propose a list of addresses that can update commission share parameters", - UsageText: "rocketpool api pdao propose-allow-listed-controllers addresses block-number", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if c.NArg() > 3 || c.NArg() < 1 { - return fmt.Errorf("Incorrect argument count;") - } - - var addressList []common.Address - var blockNumber uint32 - var err error - - // Handles a case where an empty addressList is passed, to propose an empty addressList - if c.NArg() == 1 { - blockNumber, err = cliutils.ValidateUint32("blockNumber", c.Args().Get(0)) - if err != nil { - return err - } - } else { - addressList, err = cliutils.ValidateAddresses("addressList", c.Args().Get(0)) - if err != nil { - return err - } - blockNumber, err = cliutils.ValidateUint32("blockNumber", c.Args().Get(1)) - if err != nil { - return err - } - } - - // Run - api.PrintResponse(proposeAllowListedControllers(c, addressList, blockNumber)) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/pdao/defeat-proposal.go b/rocketpool/api/pdao/defeat-proposal.go index d3e6f601b..2d3a7ced1 100644 --- a/rocketpool/api/pdao/defeat-proposal.go +++ b/rocketpool/api/pdao/defeat-proposal.go @@ -1,9 +1,10 @@ package pdao import ( - "fmt" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/types" "github.com/urfave/cli/v3" @@ -11,7 +12,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canDefeatProposal(c *cli.Command, proposalId uint64, index uint64) (*api.PDAOCanDefeatProposalResponse, error) { @@ -108,7 +108,7 @@ func canDefeatProposal(c *cli.Command, proposalId uint64, index uint64) (*api.PD return &response, nil } -func defeatProposal(c *cli.Command, proposalId uint64, index uint64) (*api.PDAODefeatProposalResponse, error) { +func defeatProposal(c *cli.Command, proposalId uint64, index uint64, opts *bind.TransactOpts) (*api.PDAODefeatProposalResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { return nil, err @@ -116,10 +116,6 @@ func defeatProposal(c *cli.Command, proposalId uint64, index uint64) (*api.PDAOD if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -128,18 +124,6 @@ func defeatProposal(c *cli.Command, proposalId uint64, index uint64) (*api.PDAOD // Response response := api.PDAODefeatProposalResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Execute proposal hash, err := protocol.DefeatProposal(rp, proposalId, index, opts) if err != nil { diff --git a/rocketpool/api/pdao/execute-proposal.go b/rocketpool/api/pdao/execute-proposal.go index 597db0881..a6680e556 100644 --- a/rocketpool/api/pdao/execute-proposal.go +++ b/rocketpool/api/pdao/execute-proposal.go @@ -1,7 +1,7 @@ package pdao import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao/protocol" rptypes "github.com/rocket-pool/smartnode/bindings/types" @@ -10,7 +10,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canExecuteProposal(c *cli.Command, proposalId uint64) (*api.CanExecutePDAOProposalResponse, error) { @@ -79,7 +78,7 @@ func canExecuteProposal(c *cli.Command, proposalId uint64) (*api.CanExecutePDAOP } -func executeProposal(c *cli.Command, proposalId uint64) (*api.ExecutePDAOProposalResponse, error) { +func executeProposal(c *cli.Command, proposalId uint64, opts *bind.TransactOpts) (*api.ExecutePDAOProposalResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -88,10 +87,6 @@ func executeProposal(c *cli.Command, proposalId uint64) (*api.ExecutePDAOProposa if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -100,18 +95,6 @@ func executeProposal(c *cli.Command, proposalId uint64) (*api.ExecutePDAOProposa // Response response := api.ExecutePDAOProposalResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Execute proposal hash, err := protocol.ExecuteProposal(rp, proposalId, opts) if err != nil { diff --git a/rocketpool/api/pdao/finalize-proposal.go b/rocketpool/api/pdao/finalize-proposal.go index 0ac0a805b..05f04a330 100644 --- a/rocketpool/api/pdao/finalize-proposal.go +++ b/rocketpool/api/pdao/finalize-proposal.go @@ -1,7 +1,7 @@ package pdao import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/types" @@ -10,7 +10,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canFinalizeProposal(c *cli.Command, proposalId uint64) (*api.PDAOCanFinalizeProposalResponse, error) { @@ -87,7 +86,7 @@ func canFinalizeProposal(c *cli.Command, proposalId uint64) (*api.PDAOCanFinaliz return &response, nil } -func finalizeProposal(c *cli.Command, proposalId uint64) (*api.PDAOFinalizeProposalResponse, error) { +func finalizeProposal(c *cli.Command, proposalId uint64, opts *bind.TransactOpts) (*api.PDAOFinalizeProposalResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { return nil, err @@ -95,10 +94,6 @@ func finalizeProposal(c *cli.Command, proposalId uint64) (*api.PDAOFinalizePropo if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -107,18 +102,6 @@ func finalizeProposal(c *cli.Command, proposalId uint64) (*api.PDAOFinalizePropo // Response response := api.PDAOFinalizeProposalResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Execute proposal hash, err := protocol.Finalize(rp, proposalId, opts) if err != nil { diff --git a/rocketpool/api/pdao/invite-security.go b/rocketpool/api/pdao/invite-security.go index 99c8846c0..896ef8c79 100644 --- a/rocketpool/api/pdao/invite-security.go +++ b/rocketpool/api/pdao/invite-security.go @@ -3,13 +3,13 @@ package pdao import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/dao/security" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" ) @@ -97,16 +97,12 @@ func canProposeInviteToSecurityCouncil(c *cli.Command, id string, address common return &response, nil } -func proposeInviteToSecurityCouncil(c *cli.Command, id string, address common.Address, blockNumber uint32) (*api.PDAOProposeInviteToSecurityCouncilResponse, error) { +func proposeInviteToSecurityCouncil(c *cli.Command, id string, address common.Address, blockNumber uint32, opts *bind.TransactOpts) (*api.PDAOProposeInviteToSecurityCouncilResponse, error) { // Get services cfg, err := services.GetConfig(c) if err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -119,18 +115,6 @@ func proposeInviteToSecurityCouncil(c *cli.Command, id string, address common.Ad // Response response := api.PDAOProposeInviteToSecurityCouncilResponse{} - // Get node account - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Propose message := fmt.Sprintf("invite %s (%s) to the security council", id, address.Hex()) pollard, err := getPollard(rp, cfg, bc, blockNumber) diff --git a/rocketpool/api/pdao/kick-multi-security.go b/rocketpool/api/pdao/kick-multi-security.go index 85c78d51f..365b99f7d 100644 --- a/rocketpool/api/pdao/kick-multi-security.go +++ b/rocketpool/api/pdao/kick-multi-security.go @@ -1,13 +1,11 @@ package pdao import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -56,16 +54,12 @@ func canProposeKickMultiFromSecurityCouncil(c *cli.Command, addresses []common.A return &response, nil } -func proposeKickMultiFromSecurityCouncil(c *cli.Command, addresses []common.Address, blockNumber uint32) (*api.PDAOProposeKickMultiFromSecurityCouncilResponse, error) { +func proposeKickMultiFromSecurityCouncil(c *cli.Command, addresses []common.Address, blockNumber uint32, opts *bind.TransactOpts) (*api.PDAOProposeKickMultiFromSecurityCouncilResponse, error) { // Get services cfg, err := services.GetConfig(c) if err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -78,18 +72,6 @@ func proposeKickMultiFromSecurityCouncil(c *cli.Command, addresses []common.Addr // Response response := api.PDAOProposeKickMultiFromSecurityCouncilResponse{} - // Get node account - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Propose message := "kick multiple members from the security council" pollard, err := getPollard(rp, cfg, bc, blockNumber) diff --git a/rocketpool/api/pdao/kick-security.go b/rocketpool/api/pdao/kick-security.go index e846b4afa..4c0fcd257 100644 --- a/rocketpool/api/pdao/kick-security.go +++ b/rocketpool/api/pdao/kick-security.go @@ -3,12 +3,12 @@ package pdao import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -81,16 +81,12 @@ func canProposeKickFromSecurityCouncil(c *cli.Command, address common.Address) ( return &response, nil } -func proposeKickFromSecurityCouncil(c *cli.Command, address common.Address, blockNumber uint32) (*api.PDAOProposeKickFromSecurityCouncilResponse, error) { +func proposeKickFromSecurityCouncil(c *cli.Command, address common.Address, blockNumber uint32, opts *bind.TransactOpts) (*api.PDAOProposeKickFromSecurityCouncilResponse, error) { // Get services cfg, err := services.GetConfig(c) if err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -103,18 +99,6 @@ func proposeKickFromSecurityCouncil(c *cli.Command, address common.Address, bloc // Response response := api.PDAOProposeKickFromSecurityCouncilResponse{} - // Get node account - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Propose message := fmt.Sprintf("kick %s from the security council", address.Hex()) pollard, err := getPollard(rp, cfg, bc, blockNumber) diff --git a/rocketpool/api/pdao/one-time-spend.go b/rocketpool/api/pdao/one-time-spend.go index 5eaac52a1..47c25259f 100644 --- a/rocketpool/api/pdao/one-time-spend.go +++ b/rocketpool/api/pdao/one-time-spend.go @@ -1,15 +1,14 @@ package pdao import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -81,16 +80,12 @@ func canProposeOneTimeSpend(c *cli.Command, invoiceID string, recipient common.A return &response, nil } -func proposeOneTimeSpend(c *cli.Command, invoiceID string, recipient common.Address, amount *big.Int, blockNumber uint32, customMessage string) (*api.PDAOProposeOneTimeSpendResponse, error) { +func proposeOneTimeSpend(c *cli.Command, invoiceID string, recipient common.Address, amount *big.Int, blockNumber uint32, customMessage string, opts *bind.TransactOpts) (*api.PDAOProposeOneTimeSpendResponse, error) { // Get services cfg, err := services.GetConfig(c) if err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -103,18 +98,6 @@ func proposeOneTimeSpend(c *cli.Command, invoiceID string, recipient common.Addr // Response response := api.PDAOProposeOneTimeSpendResponse{} - // Get node account - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Propose pollard, err := getPollard(rp, cfg, bc, blockNumber) if err != nil { diff --git a/rocketpool/api/pdao/override-vote.go b/rocketpool/api/pdao/override-vote.go index 6d73ffb78..33595e5a1 100644 --- a/rocketpool/api/pdao/override-vote.go +++ b/rocketpool/api/pdao/override-vote.go @@ -1,8 +1,7 @@ package pdao import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/network" @@ -12,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canOverrideVote(c *cli.Command, proposalId uint64, voteDirection types.VoteDirection) (*api.CanVoteOnPDAOProposalResponse, error) { @@ -106,12 +104,8 @@ func canOverrideVote(c *cli.Command, proposalId uint64, voteDirection types.Vote return &response, nil } -func overrideVote(c *cli.Command, proposalId uint64, voteDirection types.VoteDirection) (*api.VoteOnPDAOProposalResponse, error) { +func overrideVote(c *cli.Command, proposalId uint64, voteDirection types.VoteDirection, opts *bind.TransactOpts) (*api.VoteOnPDAOProposalResponse, error) { // Get services - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -120,18 +114,6 @@ func overrideVote(c *cli.Command, proposalId uint64, voteDirection types.VoteDir // Response response := api.VoteOnPDAOProposalResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Vote on proposal hash, err := protocol.OverrideVote(rp, proposalId, voteDirection, opts) if err != nil { diff --git a/rocketpool/api/pdao/percentages.go b/rocketpool/api/pdao/percentages.go index a35c621ec..4e8c7fdd9 100644 --- a/rocketpool/api/pdao/percentages.go +++ b/rocketpool/api/pdao/percentages.go @@ -4,13 +4,14 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/rocket-pool/smartnode/bindings/dao/protocol" rpnode "github.com/rocket-pool/smartnode/bindings/node" psettings "github.com/rocket-pool/smartnode/bindings/settings/protocol" "github.com/rocket-pool/smartnode/bindings/utils/eth" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -125,7 +126,7 @@ func canProposeRewardsPercentages(c *cli.Command, node *big.Int, odao *big.Int, return &response, nil } -func proposeRewardsPercentages(c *cli.Command, node *big.Int, odao *big.Int, pdao *big.Int, blockNumber uint32) (*api.PDAOProposeRewardsPercentagesResponse, error) { +func proposeRewardsPercentages(c *cli.Command, node *big.Int, odao *big.Int, pdao *big.Int, blockNumber uint32, opts *bind.TransactOpts) (*api.PDAOProposeRewardsPercentagesResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { return nil, err @@ -137,10 +138,6 @@ func proposeRewardsPercentages(c *cli.Command, node *big.Int, odao *big.Int, pda if err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -154,23 +151,12 @@ func proposeRewardsPercentages(c *cli.Command, node *big.Int, odao *big.Int, pda response := api.PDAOProposeRewardsPercentagesResponse{} // Get the account transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - // Decode the pollard pollard, err := getPollard(rp, cfg, bc, blockNumber) if err != nil { return nil, fmt.Errorf("error regenerating pollard: %w", err) } - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit the proposal proposalID, hash, err := protocol.ProposeSetRewardsPercentage(rp, "update RPL rewards distribution", odao, pdao, node, blockNumber, pollard, opts) if err != nil { diff --git a/rocketpool/api/pdao/propose-settings.go b/rocketpool/api/pdao/propose-settings.go index 76b65e5b2..ef42e6def 100644 --- a/rocketpool/api/pdao/propose-settings.go +++ b/rocketpool/api/pdao/propose-settings.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" protocol131 "github.com/rocket-pool/smartnode/bindings/legacy/v1.3.1/protocol" @@ -13,7 +14,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" ) @@ -939,7 +939,7 @@ func canProposeSetting(c *cli.Command, contractName string, settingName string, } -func proposeSetting(c *cli.Command, contractName string, settingName string, value string, blockNumber uint32) (*api.ProposePDAOSettingResponse, error) { +func proposeSetting(c *cli.Command, contractName string, settingName string, value string, blockNumber uint32, opts *bind.TransactOpts) (*api.ProposePDAOSettingResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -952,10 +952,6 @@ func proposeSetting(c *cli.Command, contractName string, settingName string, val if err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -974,18 +970,6 @@ func proposeSetting(c *cli.Command, contractName string, settingName string, val return nil, fmt.Errorf("error regenerating pollard: %w", err) } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit the proposal var proposalID uint64 var hash common.Hash diff --git a/rocketpool/api/pdao/recurring-spend.go b/rocketpool/api/pdao/recurring-spend.go index 7138a8ce6..1430d1efb 100644 --- a/rocketpool/api/pdao/recurring-spend.go +++ b/rocketpool/api/pdao/recurring-spend.go @@ -1,16 +1,15 @@ package pdao import ( - "fmt" "math/big" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -82,16 +81,12 @@ func canProposeRecurringSpend(c *cli.Command, contractName string, recipient com return &response, nil } -func proposeRecurringSpend(c *cli.Command, contractName string, recipient common.Address, amountPerPeriod *big.Int, periodLength time.Duration, startTime time.Time, numberOfPeriods uint64, blockNumber uint32, customMessage string) (*api.PDAOProposeOneTimeSpendResponse, error) { +func proposeRecurringSpend(c *cli.Command, contractName string, recipient common.Address, amountPerPeriod *big.Int, periodLength time.Duration, startTime time.Time, numberOfPeriods uint64, blockNumber uint32, customMessage string, opts *bind.TransactOpts) (*api.PDAOProposeOneTimeSpendResponse, error) { // Get services cfg, err := services.GetConfig(c) if err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -104,18 +99,6 @@ func proposeRecurringSpend(c *cli.Command, contractName string, recipient common // Response response := api.PDAOProposeOneTimeSpendResponse{} - // Get node account - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Propose pollard, err := getPollard(rp, cfg, bc, blockNumber) diff --git a/rocketpool/api/pdao/replace-security.go b/rocketpool/api/pdao/replace-security.go index 68b492b40..047b2dd4e 100644 --- a/rocketpool/api/pdao/replace-security.go +++ b/rocketpool/api/pdao/replace-security.go @@ -3,13 +3,13 @@ package pdao import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/dao/security" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -88,16 +88,12 @@ func canProposeReplaceMemberOfSecurityCouncil(c *cli.Command, existingMemberAddr return &response, nil } -func proposeReplaceMemberOfSecurityCouncil(c *cli.Command, existingMemberAddress common.Address, newMemberID string, newMemberAddress common.Address, blockNumber uint32) (*api.PDAOProposeReplaceMemberOfSecurityCouncilResponse, error) { +func proposeReplaceMemberOfSecurityCouncil(c *cli.Command, existingMemberAddress common.Address, newMemberID string, newMemberAddress common.Address, blockNumber uint32, opts *bind.TransactOpts) (*api.PDAOProposeReplaceMemberOfSecurityCouncilResponse, error) { // Get services cfg, err := services.GetConfig(c) if err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -111,23 +107,12 @@ func proposeReplaceMemberOfSecurityCouncil(c *cli.Command, existingMemberAddress response := api.PDAOProposeReplaceMemberOfSecurityCouncilResponse{} // Get node account - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - // Get the existing member existingID, err := security.GetMemberID(rp, existingMemberAddress, nil) if err != nil { return nil, fmt.Errorf("error getting ID of existing member: %w", err) } - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Propose message := fmt.Sprintf("replace %s (%s) on the security council with %s (%s)", existingID, existingMemberAddress.Hex(), newMemberID, newMemberAddress.Hex()) pollard, err := getPollard(rp, cfg, bc, blockNumber) diff --git a/rocketpool/api/pdao/routes.go b/rocketpool/api/pdao/routes.go new file mode 100644 index 000000000..ae09560fd --- /dev/null +++ b/rocketpool/api/pdao/routes.go @@ -0,0 +1,703 @@ +package pdao + +import ( + "fmt" + "math/big" + "net/http" + "strconv" + "strings" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/urfave/cli/v3" + + bindtypes "github.com/rocket-pool/smartnode/bindings/types" + "github.com/rocket-pool/smartnode/shared/services" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" + cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" +) + +// RegisterRoutes registers the pdao module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/pdao/status", func(w http.ResponseWriter, r *http.Request) { + resp, err := getStatus(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/proposals", func(w http.ResponseWriter, r *http.Request) { + resp, err := getProposals(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/proposal-details", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64Param(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := getProposal(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-vote-proposal", func(w http.ResponseWriter, r *http.Request) { + id, voteDir, err := parseProposalVoteParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canVoteOnProposal(c, id, voteDir) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/vote-proposal", func(w http.ResponseWriter, r *http.Request) { + id, voteDir, err := parseProposalVoteParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := voteOnProposal(c, id, voteDir, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-override-vote", func(w http.ResponseWriter, r *http.Request) { + id, voteDir, err := parseProposalVoteParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canOverrideVote(c, id, voteDir) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/override-vote", func(w http.ResponseWriter, r *http.Request) { + id, voteDir, err := parseProposalVoteParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := overrideVote(c, id, voteDir, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-execute-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64Param(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canExecuteProposal(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/execute-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64Param(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := executeProposal(c, id, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/get-settings", func(w http.ResponseWriter, r *http.Request) { + resp, err := getSettings(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-propose-setting", func(w http.ResponseWriter, r *http.Request) { + contract := paramVal(r, "contract") + setting := paramVal(r, "setting") + value := paramVal(r, "value") + resp, err := canProposeSetting(c, contract, setting, value) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/propose-setting", func(w http.ResponseWriter, r *http.Request) { + contract := paramVal(r, "contract") + setting := paramVal(r, "setting") + value := paramVal(r, "value") + blockNumber, err := parseUint32Param(r, "blockNumber") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSetting(c, contract, setting, value, blockNumber, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/get-rewards-percentages", func(w http.ResponseWriter, r *http.Request) { + resp, err := getRewardsPercentages(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-propose-rewards-percentages", func(w http.ResponseWriter, r *http.Request) { + node, odaoAmt, pdaoAmt, err := parseRewardPercentages(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeRewardsPercentages(c, node, odaoAmt, pdaoAmt) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/propose-rewards-percentages", func(w http.ResponseWriter, r *http.Request) { + node, odaoAmt, pdaoAmt, err := parseRewardPercentages(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + blockNumber, err := parseUint32Param(r, "blockNumber") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeRewardsPercentages(c, node, odaoAmt, pdaoAmt, blockNumber, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-propose-one-time-spend", func(w http.ResponseWriter, r *http.Request) { + invoiceID, recipient, amount, customMessage, err := parseOneTimeSpendParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeOneTimeSpend(c, invoiceID, recipient, amount, customMessage) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/propose-one-time-spend", func(w http.ResponseWriter, r *http.Request) { + invoiceID, recipient, amount, customMessage, err := parseOneTimeSpendParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + blockNumber, err := parseUint32Param(r, "blockNumber") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeOneTimeSpend(c, invoiceID, recipient, amount, blockNumber, customMessage, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-propose-recurring-spend", func(w http.ResponseWriter, r *http.Request) { + contractName, recipient, amountPerPeriod, periodLength, startTime, numberOfPeriods, customMessage, err := parseRecurringSpendParams(r, false) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeRecurringSpend(c, contractName, recipient, amountPerPeriod, periodLength, startTime, numberOfPeriods, customMessage) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/propose-recurring-spend", func(w http.ResponseWriter, r *http.Request) { + contractName, recipient, amountPerPeriod, periodLength, startTime, numberOfPeriods, customMessage, err := parseRecurringSpendParams(r, false) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + blockNumber, err := parseUint32Param(r, "blockNumber") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeRecurringSpend(c, contractName, recipient, amountPerPeriod, periodLength, startTime, numberOfPeriods, blockNumber, customMessage, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-propose-recurring-spend-update", func(w http.ResponseWriter, r *http.Request) { + contractName, recipient, amountPerPeriod, periodLength, _, numberOfPeriods, customMessage, err := parseRecurringSpendParams(r, true) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeRecurringSpendUpdate(c, contractName, recipient, amountPerPeriod, periodLength, numberOfPeriods, customMessage) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/propose-recurring-spend-update", func(w http.ResponseWriter, r *http.Request) { + contractName, recipient, amountPerPeriod, periodLength, _, numberOfPeriods, customMessage, err := parseRecurringSpendParams(r, true) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + blockNumber, err := parseUint32Param(r, "blockNumber") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeRecurringSpendUpdate(c, contractName, recipient, amountPerPeriod, periodLength, numberOfPeriods, blockNumber, customMessage, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-propose-invite-to-security-council", func(w http.ResponseWriter, r *http.Request) { + id := paramVal(r, "id") + addr := common.HexToAddress(paramVal(r, "address")) + resp, err := canProposeInviteToSecurityCouncil(c, id, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/propose-invite-to-security-council", func(w http.ResponseWriter, r *http.Request) { + id := paramVal(r, "id") + addr := common.HexToAddress(paramVal(r, "address")) + blockNumber, err := parseUint32Param(r, "blockNumber") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeInviteToSecurityCouncil(c, id, addr, blockNumber, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-propose-kick-from-security-council", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(paramVal(r, "address")) + resp, err := canProposeKickFromSecurityCouncil(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/propose-kick-from-security-council", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(paramVal(r, "address")) + blockNumber, err := parseUint32Param(r, "blockNumber") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeKickFromSecurityCouncil(c, addr, blockNumber, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-propose-kick-multi-from-security-council", func(w http.ResponseWriter, r *http.Request) { + addresses, err := parseAddressList(r, "addresses") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProposeKickMultiFromSecurityCouncil(c, addresses) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/propose-kick-multi-from-security-council", func(w http.ResponseWriter, r *http.Request) { + addresses, err := parseAddressList(r, "addresses") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + blockNumber, err := parseUint32Param(r, "blockNumber") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeKickMultiFromSecurityCouncil(c, addresses, blockNumber, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-propose-replace-member-of-security-council", func(w http.ResponseWriter, r *http.Request) { + existing := common.HexToAddress(paramVal(r, "existingAddress")) + newID := paramVal(r, "newId") + newAddr := common.HexToAddress(paramVal(r, "newAddress")) + resp, err := canProposeReplaceMemberOfSecurityCouncil(c, existing, newID, newAddr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/propose-replace-member-of-security-council", func(w http.ResponseWriter, r *http.Request) { + existing := common.HexToAddress(paramVal(r, "existingAddress")) + newID := paramVal(r, "newId") + newAddr := common.HexToAddress(paramVal(r, "newAddress")) + blockNumber, err := parseUint32Param(r, "blockNumber") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeReplaceMemberOfSecurityCouncil(c, existing, newID, newAddr, blockNumber, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/get-claimable-bonds", func(w http.ResponseWriter, r *http.Request) { + resp, err := getClaimableBonds(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-claim-bonds", func(w http.ResponseWriter, r *http.Request) { + proposalID, indices, err := parseClaimBondsParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canClaimBonds(c, proposalID, indices) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/claim-bonds", func(w http.ResponseWriter, r *http.Request) { + proposalID, indices, err := parseClaimBondsParams(r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + isProposer := paramVal(r, "isProposer") == "true" + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := claimBonds(c, isProposer, proposalID, indices, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-defeat-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64Param(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + index, err := parseUint64Param(r, "index") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canDefeatProposal(c, id, index) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/defeat-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64Param(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + index, err := parseUint64Param(r, "index") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := defeatProposal(c, id, index, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-finalize-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64Param(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canFinalizeProposal(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/finalize-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64Param(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := finalizeProposal(c, id, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/estimate-set-voting-delegate-gas", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(paramVal(r, "address")) + resp, err := estimateSetVotingDelegateGas(c, addr) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/set-voting-delegate", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(paramVal(r, "address")) + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setVotingDelegate(c, addr, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/get-current-voting-delegate", func(w http.ResponseWriter, r *http.Request) { + resp, err := getCurrentVotingDelegate(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-set-signalling-address", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(paramVal(r, "address")) + sig := paramVal(r, "signature") + resp, err := canSetSignallingAddress(c, addr, sig) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/set-signalling-address", func(w http.ResponseWriter, r *http.Request) { + addr := common.HexToAddress(paramVal(r, "address")) + sig := paramVal(r, "signature") + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setSignallingAddress(c, addr, sig, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-clear-signalling-address", func(w http.ResponseWriter, r *http.Request) { + resp, err := canClearSignallingAddress(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/clear-signalling-address", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := clearSignallingAddress(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/can-propose-allow-listed-controllers", func(w http.ResponseWriter, r *http.Request) { + addressList := paramVal(r, "addressList") + addresses, err := parseAddressList(r, "addressList") + if err != nil { + // Fall back to the raw comma-separated string if address parsing fails + addresses = parseRawAddressList(addressList) + } + resp, err := canProposeAllowListedControllers(c, addresses) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/pdao/propose-allow-listed-controllers", func(w http.ResponseWriter, r *http.Request) { + addressList := paramVal(r, "addressList") + addresses, err := parseAddressList(r, "addressList") + if err != nil { + addresses = parseRawAddressList(addressList) + } + blockNumber, err := parseUint32Param(r, "blockNumber") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeAllowListedControllers(c, addresses, blockNumber, opts) + apiutils.WriteResponse(w, resp, err) + }) +} + +func paramVal(r *http.Request, name string) string { + v := r.URL.Query().Get(name) + if v == "" { + v = r.FormValue(name) + } + return v +} + +func parseUint64Param(r *http.Request, name string) (uint64, error) { + raw := paramVal(r, name) + val, err := strconv.ParseUint(raw, 10, 64) + if err != nil { + return 0, fmt.Errorf("invalid %s: %s", name, raw) + } + return val, nil +} + +func parseUint32Param(r *http.Request, name string) (uint32, error) { + raw := paramVal(r, name) + val, err := strconv.ParseUint(raw, 10, 32) + if err != nil { + return 0, fmt.Errorf("invalid %s: %s", name, raw) + } + return uint32(val), nil +} + +func parseProposalVoteParams(r *http.Request) (uint64, bindtypes.VoteDirection, error) { + id, err := parseUint64Param(r, "id") + if err != nil { + return 0, 0, err + } + dirStr := paramVal(r, "voteDirection") + dir, err := cliutils.ValidateVoteDirection("voteDirection", dirStr) + if err != nil { + return 0, 0, err + } + return id, dir, nil +} + +func parseRewardPercentages(r *http.Request) (*big.Int, *big.Int, *big.Int, error) { + nodeStr := paramVal(r, "node") + odaoStr := paramVal(r, "odao") + pdaoStr := paramVal(r, "pdao") + + node, ok := new(big.Int).SetString(nodeStr, 10) + if !ok { + return nil, nil, nil, fmt.Errorf("invalid node percentage: %s", nodeStr) + } + odaoAmt, ok := new(big.Int).SetString(odaoStr, 10) + if !ok { + return nil, nil, nil, fmt.Errorf("invalid odao percentage: %s", odaoStr) + } + pdaoAmt, ok := new(big.Int).SetString(pdaoStr, 10) + if !ok { + return nil, nil, nil, fmt.Errorf("invalid pdao percentage: %s", pdaoStr) + } + return node, odaoAmt, pdaoAmt, nil +} + +func parseOneTimeSpendParams(r *http.Request) (string, common.Address, *big.Int, string, error) { + invoiceID := paramVal(r, "invoiceId") + recipient := common.HexToAddress(paramVal(r, "recipient")) + amountStr := paramVal(r, "amount") + amount, ok := new(big.Int).SetString(amountStr, 10) + if !ok { + return "", common.Address{}, nil, "", fmt.Errorf("invalid amount: %s", amountStr) + } + customMessage := paramVal(r, "customMessage") + return invoiceID, recipient, amount, customMessage, nil +} + +// parseRecurringSpendParams parses recurring spend parameters. +// If skipStartTime is true, the startTime is omitted (for update operations). +func parseRecurringSpendParams(r *http.Request, skipStartTime bool) (string, common.Address, *big.Int, time.Duration, time.Time, uint64, string, error) { + contractName := paramVal(r, "contractName") + recipient := common.HexToAddress(paramVal(r, "recipient")) + + amountStr := paramVal(r, "amountPerPeriod") + amount, ok := new(big.Int).SetString(amountStr, 10) + if !ok { + return "", common.Address{}, nil, 0, time.Time{}, 0, "", fmt.Errorf("invalid amountPerPeriod: %s", amountStr) + } + + periodLengthStr := paramVal(r, "periodLength") + periodLength, err := time.ParseDuration(periodLengthStr) + if err != nil { + return "", common.Address{}, nil, 0, time.Time{}, 0, "", fmt.Errorf("invalid periodLength: %s", periodLengthStr) + } + + var startTime time.Time + if !skipStartTime { + startTimeStr := paramVal(r, "startTime") + startTimeUnix, err := strconv.ParseInt(startTimeStr, 10, 64) + if err != nil { + return "", common.Address{}, nil, 0, time.Time{}, 0, "", fmt.Errorf("invalid startTime: %s", startTimeStr) + } + startTime = time.Unix(startTimeUnix, 0) + } + + numberOfPeriodsStr := paramVal(r, "numberOfPeriods") + numberOfPeriods, err := strconv.ParseUint(numberOfPeriodsStr, 10, 64) + if err != nil { + return "", common.Address{}, nil, 0, time.Time{}, 0, "", fmt.Errorf("invalid numberOfPeriods: %s", numberOfPeriodsStr) + } + + customMessage := paramVal(r, "customMessage") + return contractName, recipient, amount, periodLength, startTime, numberOfPeriods, customMessage, nil +} + +func parseAddressList(r *http.Request, name string) ([]common.Address, error) { + raw := paramVal(r, name) + if raw == "" { + return nil, fmt.Errorf("missing required parameter: %s", name) + } + return parseRawAddressList(raw), nil +} + +func parseRawAddressList(raw string) []common.Address { + parts := strings.Split(raw, ",") + addresses := make([]common.Address, 0, len(parts)) + for _, p := range parts { + p = strings.TrimSpace(p) + if p != "" { + addresses = append(addresses, common.HexToAddress(p)) + } + } + return addresses +} + +func parseClaimBondsParams(r *http.Request) (uint64, []uint64, error) { + proposalID, err := parseUint64Param(r, "proposalId") + if err != nil { + return 0, nil, err + } + indicesStr := paramVal(r, "indices") + parts := strings.Split(indicesStr, ",") + indices := make([]uint64, 0, len(parts)) + for _, p := range parts { + p = strings.TrimSpace(p) + if p == "" { + continue + } + idx, err := strconv.ParseUint(p, 10, 64) + if err != nil { + return 0, nil, fmt.Errorf("invalid index: %s", p) + } + indices = append(indices, idx) + } + return proposalID, indices, nil +} diff --git a/rocketpool/api/pdao/set-allow-list.go b/rocketpool/api/pdao/set-allow-list.go index dde59a23a..dfc867104 100644 --- a/rocketpool/api/pdao/set-allow-list.go +++ b/rocketpool/api/pdao/set-allow-list.go @@ -1,14 +1,12 @@ package pdao import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/bindings/settings/protocol" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -80,16 +78,12 @@ func canProposeAllowListedControllers(c *cli.Command, addressList []common.Addre return &response, nil } -func proposeAllowListedControllers(c *cli.Command, addressList []common.Address, blockNumber uint32) (*api.PDAOProposeAllowListedControllersResponse, error) { +func proposeAllowListedControllers(c *cli.Command, addressList []common.Address, blockNumber uint32, opts *bind.TransactOpts) (*api.PDAOProposeAllowListedControllersResponse, error) { // Get services cfg, err := services.GetConfig(c) if err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -102,18 +96,6 @@ func proposeAllowListedControllers(c *cli.Command, addressList []common.Address, // Response response := api.PDAOProposeAllowListedControllersResponse{} - // Get node account - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Propose pollard, err := getPollard(rp, cfg, bc, blockNumber) if err != nil { diff --git a/rocketpool/api/pdao/set-snapshot-address.go b/rocketpool/api/pdao/set-snapshot-address.go index 44809fa92..a0f1a677e 100644 --- a/rocketpool/api/pdao/set-snapshot-address.go +++ b/rocketpool/api/pdao/set-snapshot-address.go @@ -13,7 +13,6 @@ import ( "github.com/rocket-pool/smartnode/shared/types/api" cfgtypes "github.com/rocket-pool/smartnode/shared/types/config" apiutils "github.com/rocket-pool/smartnode/shared/utils/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -107,16 +106,12 @@ func canSetSignallingAddress(c *cli.Command, signallingAddress common.Address, s return &response, nil } -func setSignallingAddress(c *cli.Command, signallingAddress common.Address, signature string) (*api.PDAOSetSignallingAddressResponse, error) { +func setSignallingAddress(c *cli.Command, signallingAddress common.Address, signature string, opts *bind.TransactOpts) (*api.PDAOSetSignallingAddressResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } cfg, err := services.GetConfig(c) if err != nil { return nil, err @@ -138,18 +133,6 @@ func setSignallingAddress(c *cli.Command, signallingAddress common.Address, sign fmt.Println("Error parsing signature", err) } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Call SetSigner on RocketSignerRegistry tx, err := reg.SetSigner(opts, signallingAddress, sig.V, sig.R, sig.S) if err != nil { @@ -243,15 +226,11 @@ func canClearSignallingAddress(c *cli.Command) (*api.PDAOCanClearSignallingAddre return &response, nil } -func clearSignallingAddress(c *cli.Command) (*api.PDAOClearSignallingAddressResponse, error) { +func clearSignallingAddress(c *cli.Command, opts *bind.TransactOpts) (*api.PDAOClearSignallingAddressResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } cfg, err := services.GetConfig(c) if err != nil { return nil, err @@ -266,18 +245,6 @@ func clearSignallingAddress(c *cli.Command) (*api.PDAOClearSignallingAddressResp response := api.PDAOClearSignallingAddressResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Clear the signalling address tx, err := reg.ClearSigner(opts) if err != nil { diff --git a/rocketpool/api/pdao/update-recurring-spend.go b/rocketpool/api/pdao/update-recurring-spend.go index 60150ce9c..77a2916df 100644 --- a/rocketpool/api/pdao/update-recurring-spend.go +++ b/rocketpool/api/pdao/update-recurring-spend.go @@ -1,16 +1,15 @@ package pdao import ( - "fmt" "math/big" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/node" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -82,16 +81,12 @@ func canProposeRecurringSpendUpdate(c *cli.Command, contractName string, recipie return &response, nil } -func proposeRecurringSpendUpdate(c *cli.Command, contractName string, recipient common.Address, amountPerPeriod *big.Int, periodLength time.Duration, numberOfPeriods uint64, blockNumber uint32, customMessage string) (*api.PDAOProposeOneTimeSpendResponse, error) { +func proposeRecurringSpendUpdate(c *cli.Command, contractName string, recipient common.Address, amountPerPeriod *big.Int, periodLength time.Duration, numberOfPeriods uint64, blockNumber uint32, customMessage string, opts *bind.TransactOpts) (*api.PDAOProposeOneTimeSpendResponse, error) { // Get services cfg, err := services.GetConfig(c) if err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -104,18 +99,6 @@ func proposeRecurringSpendUpdate(c *cli.Command, contractName string, recipient // Response response := api.PDAOProposeOneTimeSpendResponse{} - // Get node account - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Propose pollard, err := getPollard(rp, cfg, bc, blockNumber) if err != nil { diff --git a/rocketpool/api/pdao/vote-proposal.go b/rocketpool/api/pdao/vote-proposal.go index e08b30f65..6cb3ad237 100644 --- a/rocketpool/api/pdao/vote-proposal.go +++ b/rocketpool/api/pdao/vote-proposal.go @@ -1,8 +1,7 @@ package pdao import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/dao/protocol" "github.com/rocket-pool/smartnode/bindings/types" @@ -12,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/services/proposals" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canVoteOnProposal(c *cli.Command, proposalId uint64, voteDirection types.VoteDirection) (*api.CanVoteOnPDAOProposalResponse, error) { @@ -120,7 +118,7 @@ func canVoteOnProposal(c *cli.Command, proposalId uint64, voteDirection types.Vo return &response, nil } -func voteOnProposal(c *cli.Command, proposalId uint64, voteDirection types.VoteDirection) (*api.VoteOnPDAOProposalResponse, error) { +func voteOnProposal(c *cli.Command, proposalId uint64, voteDirection types.VoteDirection, opts *bind.TransactOpts) (*api.VoteOnPDAOProposalResponse, error) { // Get services cfg, err := services.GetConfig(c) if err != nil { @@ -148,12 +146,6 @@ func voteOnProposal(c *cli.Command, proposalId uint64, voteDirection types.VoteD return nil, err } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - // Get the block used by the proposal proposalBlock, err := protocol.GetProposalBlock(rp, proposalId, nil) if err != nil { @@ -170,12 +162,6 @@ func voteOnProposal(c *cli.Command, proposalId uint64, voteDirection types.VoteD return nil, err } - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Vote on proposal hash, err := protocol.VoteOnProposal(rp, proposalId, voteDirection, totalDelegatedVP, nodeIndex, proof, opts) if err != nil { diff --git a/rocketpool/api/pdao/voting.go b/rocketpool/api/pdao/voting.go index 50eddf953..fabf4095f 100644 --- a/rocketpool/api/pdao/voting.go +++ b/rocketpool/api/pdao/voting.go @@ -1,15 +1,13 @@ package pdao import ( - "fmt" - + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/bindings/network" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func estimateSetVotingDelegateGas(c *cli.Command, address common.Address) (*api.PDAOCanSetVotingDelegateResponse, error) { @@ -48,7 +46,7 @@ func estimateSetVotingDelegateGas(c *cli.Command, address common.Address) (*api. } -func setVotingDelegate(c *cli.Command, address common.Address) (*api.PDAOSetVotingDelegateResponse, error) { +func setVotingDelegate(c *cli.Command, address common.Address, opts *bind.TransactOpts) (*api.PDAOSetVotingDelegateResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -58,26 +56,9 @@ func setVotingDelegate(c *cli.Command, address common.Address) (*api.PDAOSetVoti if err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } - // Response response := api.PDAOSetVotingDelegateResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Set the delegate tx, err := network.SetVotingDelegate(rp, address, opts) if err != nil { diff --git a/rocketpool/api/queue/assign-deposits.go b/rocketpool/api/queue/assign-deposits.go index 3344ee622..014e527a9 100644 --- a/rocketpool/api/queue/assign-deposits.go +++ b/rocketpool/api/queue/assign-deposits.go @@ -1,9 +1,9 @@ package queue import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/deposit" "github.com/rocket-pool/smartnode/bindings/settings/protocol" "github.com/urfave/cli/v3" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canAssignDeposits(c *cli.Command, max int64) (*api.CanAssignDepositsResponse, error) { @@ -70,7 +69,7 @@ func canAssignDeposits(c *cli.Command, max int64) (*api.CanAssignDepositsRespons } -func assignDeposits(c *cli.Command, max int64) (*api.AssignDepositsResponse, error) { +func assignDeposits(c *cli.Command, max int64, opts *bind.TransactOpts) (*api.AssignDepositsResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -79,10 +78,6 @@ func assignDeposits(c *cli.Command, max int64) (*api.AssignDepositsResponse, err if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -91,18 +86,6 @@ func assignDeposits(c *cli.Command, max int64) (*api.AssignDepositsResponse, err // Response response := api.AssignDepositsResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Assign deposits hash, err := deposit.AssignDeposits(rp, big.NewInt(max), opts) if err != nil { diff --git a/rocketpool/api/queue/commands.go b/rocketpool/api/queue/commands.go deleted file mode 100644 index bc9862546..000000000 --- a/rocketpool/api/queue/commands.go +++ /dev/null @@ -1,149 +0,0 @@ -package queue - -import ( - "context" - - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage the Rocket Pool deposit queue", - Commands: []*cli.Command{ - - { - Name: "status", - Aliases: []string{"s"}, - Usage: "Get the deposit pool and minipool queue status", - UsageText: "rocketpool api queue status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getStatus(c)) - return nil - - }, - }, - - { - Name: "can-process", - Usage: "Check whether the deposit pool can be processed", - UsageText: "rocketpool api queue can-process max-validators", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - max, err := cliutils.ValidatePositiveUint32("max-validators", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canProcessQueue(c, int64(max))) - return nil - - }, - }, - { - Name: "process", - Aliases: []string{"p"}, - Usage: "Process the deposit pool", - UsageText: "rocketpool api queue process max-validators", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - max, err := cliutils.ValidatePositiveUint32("max-validators", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(processQueue(c, int64(max))) - return nil - - }, - }, - { - Name: "get-queue-details", - Usage: "Gets queue details.", - UsageText: "rocketpool api queue get-queue-details", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getQueueDetails(c)) - return nil - - }, - }, - - { - Name: "can-assign-deposits", - Usage: "Check whether deposits can be assigned", - UsageText: "rocketpool api queue can-assign-deposits max", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - max, err := cliutils.ValidatePositiveUint32("max", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canAssignDeposits(c, int64(max))) - return nil - - }, - }, - { - Name: "assign-deposits", - Aliases: []string{"ad"}, - Usage: "Assign deposits to queued validators", - UsageText: "rocketpool api queue assign-deposits max", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - max, err := cliutils.ValidatePositiveUint32("max", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(assignDeposits(c, int64(max))) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/queue/process.go b/rocketpool/api/queue/process.go index a37690101..2845a3ddf 100644 --- a/rocketpool/api/queue/process.go +++ b/rocketpool/api/queue/process.go @@ -1,9 +1,9 @@ package queue import ( - "fmt" "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/deposit" "github.com/rocket-pool/smartnode/bindings/settings/protocol" "github.com/urfave/cli/v3" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canProcessQueue(c *cli.Command, max int64) (*api.CanProcessQueueResponse, error) { @@ -71,7 +70,7 @@ func canProcessQueue(c *cli.Command, max int64) (*api.CanProcessQueueResponse, e } -func processQueue(c *cli.Command, max int64) (*api.ProcessQueueResponse, error) { +func processQueue(c *cli.Command, max int64, opts *bind.TransactOpts) (*api.ProcessQueueResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -80,10 +79,6 @@ func processQueue(c *cli.Command, max int64) (*api.ProcessQueueResponse, error) if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -92,18 +87,6 @@ func processQueue(c *cli.Command, max int64) (*api.ProcessQueueResponse, error) // Response response := api.ProcessQueueResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Process queue hash, err := deposit.AssignDeposits(rp, big.NewInt(max), opts) diff --git a/rocketpool/api/queue/routes.go b/rocketpool/api/queue/routes.go new file mode 100644 index 000000000..2a0e662d9 --- /dev/null +++ b/rocketpool/api/queue/routes.go @@ -0,0 +1,86 @@ +package queue + +import ( + "net/http" + "strconv" + + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/shared/services" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +// RegisterRoutes registers the queue module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/queue/status", func(w http.ResponseWriter, r *http.Request) { + resp, err := getStatus(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/queue/can-process", func(w http.ResponseWriter, r *http.Request) { + max, err := parseUint32Param(r, "max") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canProcessQueue(c, int64(max)) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/queue/process", func(w http.ResponseWriter, r *http.Request) { + max, err := parseUint32Param(r, "max") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := processQueue(c, int64(max), opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/queue/get-queue-details", func(w http.ResponseWriter, r *http.Request) { + resp, err := getQueueDetails(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/queue/can-assign-deposits", func(w http.ResponseWriter, r *http.Request) { + max, err := parseUint32Param(r, "max") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canAssignDeposits(c, int64(max)) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/queue/assign-deposits", func(w http.ResponseWriter, r *http.Request) { + max, err := parseUint32Param(r, "max") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := assignDeposits(c, int64(max), opts) + apiutils.WriteResponse(w, resp, err) + }) +} + +func parseUint32Param(r *http.Request, name string) (uint32, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + v, err := strconv.ParseUint(raw, 10, 32) + if err != nil { + return 0, err + } + return uint32(v), nil +} diff --git a/rocketpool/api/security/cancel-proposal.go b/rocketpool/api/security/cancel-proposal.go index 166bbadcf..f67c8c9b4 100644 --- a/rocketpool/api/security/cancel-proposal.go +++ b/rocketpool/api/security/cancel-proposal.go @@ -2,7 +2,8 @@ package security import ( "bytes" - "fmt" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao" "github.com/rocket-pool/smartnode/bindings/dao/security" @@ -12,7 +13,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canCancelProposal(c *cli.Command, proposalId uint64) (*api.SecurityCanCancelProposalResponse, error) { @@ -91,16 +91,12 @@ func canCancelProposal(c *cli.Command, proposalId uint64) (*api.SecurityCanCance } -func cancelProposal(c *cli.Command, proposalId uint64) (*api.SecurityCancelProposalResponse, error) { +func cancelProposal(c *cli.Command, proposalId uint64, opts *bind.TransactOpts) (*api.SecurityCancelProposalResponse, error) { // Get services if err := services.RequireNodeSecurityMember(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -109,18 +105,6 @@ func cancelProposal(c *cli.Command, proposalId uint64) (*api.SecurityCancelPropo // Response response := api.SecurityCancelProposalResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Cancel proposal hash, err := security.CancelProposal(rp, proposalId, opts) if err != nil { diff --git a/rocketpool/api/security/commands.go b/rocketpool/api/security/commands.go deleted file mode 100644 index b6037f8a2..000000000 --- a/rocketpool/api/security/commands.go +++ /dev/null @@ -1,419 +0,0 @@ -package security - -import ( - "context" - - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage the Rocket Pool security council", - Commands: []*cli.Command{ - - { - Name: "status", - Aliases: []string{"s"}, - Usage: "Get security council status", - UsageText: "rocketpool api security status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getStatus(c)) - return nil - - }, - }, - { - Name: "members", - Aliases: []string{"m"}, - Usage: "Get the security council members", - UsageText: "rocketpool api security members", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getMembers(c)) - return nil - - }, - }, - - { - Name: "proposals", - Aliases: []string{"p"}, - Usage: "Get the security council proposals", - UsageText: "rocketpool api security proposals", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getProposals(c)) - return nil - - }, - }, - - { - Name: "proposal-details", - Aliases: []string{"d"}, - Usage: "Get details of a proposal", - UsageText: "rocketpool api security proposal-details proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - var err error - if err = cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - id, err := cliutils.ValidateUint("proposal-id", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(getProposal(c, id)) - return nil - - }, - }, - { - Name: "can-propose-leave", - Usage: "Check whether the node can propose leaving the security council", - UsageText: "rocketpool api security can-propose-leave", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canProposeLeave(c)) - return nil - - }, - }, - { - Name: "propose-leave", - Aliases: []string{"l"}, - Usage: "Propose leaving the security council", - UsageText: "rocketpool api security propose-leave", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(proposeLeave(c)) - return nil - - }, - }, - { - Name: "can-leave", - Usage: "Check whether the node can leave the security council", - UsageText: "rocketpool api security can-leave", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canLeave(c)) - return nil - - }, - }, - { - Name: "leave", - Aliases: []string{"l"}, - Usage: "Leave the security council", - UsageText: "rocketpool api security propose-leave", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(leave(c)) - return nil - - }, - }, - { - Name: "can-cancel-proposal", - Usage: "Check whether the node can cancel a proposal", - UsageText: "rocketpool api security can-cancel-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canCancelProposal(c, proposalId)) - return nil - - }, - }, - { - Name: "cancel-proposal", - Aliases: []string{"c"}, - Usage: "Cancel a proposal made by the node", - UsageText: "rocketpool api security cancel-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(cancelProposal(c, proposalId)) - return nil - - }, - }, - - { - Name: "can-vote-proposal", - Usage: "Check whether the node can vote on a proposal", - UsageText: "rocketpool api security can-vote-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canVoteOnProposal(c, proposalId)) - return nil - - }, - }, - { - Name: "vote-proposal", - Aliases: []string{"v"}, - Usage: "Vote on a proposal", - UsageText: "rocketpool api security vote-proposal proposal-id support", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - support, err := cliutils.ValidateBool("support", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(voteOnProposal(c, proposalId, support)) - return nil - - }, - }, - - { - Name: "can-execute-proposal", - Usage: "Check whether the node can execute a proposal", - UsageText: "rocketpool api security can-execute-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canExecuteProposal(c, proposalId)) - return nil - - }, - }, - { - Name: "execute-proposal", - Aliases: []string{"x"}, - Usage: "Execute a proposal", - UsageText: "rocketpool api security execute-proposal proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - proposalId, err := cliutils.ValidatePositiveUint("proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(executeProposal(c, proposalId)) - return nil - - }, - }, - - { - Name: "can-join", - Usage: "Check whether the node can join the security council", - UsageText: "rocketpool api security can-join", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canJoin(c)) - return nil - - }, - }, - { - Name: "join", - Aliases: []string{"j"}, - Usage: "Join the security council (requires an executed invite proposal)", - UsageText: "rocketpool api security join", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(join(c)) - return nil - - }, - }, - - { - Name: "can-leave", - Usage: "Check whether the node can leave the security council", - UsageText: "rocketpool api security can-leave", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(canLeave(c)) - return nil - - }, - }, - { - Name: "leave", - Aliases: []string{"e"}, - Usage: "Leave the security council (requires an executed leave proposal)", - UsageText: "rocketpool api security leave", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(leave(c)) - return nil - - }, - }, - - { - Name: "can-propose-setting", - Usage: "Check whether the node can propose a PDAO setting", - UsageText: "rocketpool api security can-propose-setting contract-name setting-name value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - contractName := c.Args().Get(0) - settingName := c.Args().Get(1) - value := c.Args().Get(2) - - // Run - api.PrintResponse(canProposeSetting(c, contractName, settingName, value)) - return nil - - }, - }, - { - Name: "propose-setting", - Usage: "Propose updating a PDAO setting", - UsageText: "rocketpool api security propose-setting contract-name setting-name value", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 3); err != nil { - return err - } - contractName := c.Args().Get(0) - settingName := c.Args().Get(1) - value := c.Args().Get(2) - - // Run - api.PrintResponse(proposeSetting(c, contractName, settingName, value)) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/security/execute-proposal.go b/rocketpool/api/security/execute-proposal.go index 6a5194603..8042b6e14 100644 --- a/rocketpool/api/security/execute-proposal.go +++ b/rocketpool/api/security/execute-proposal.go @@ -1,7 +1,7 @@ package security import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao" "github.com/rocket-pool/smartnode/bindings/dao/security" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canExecuteProposal(c *cli.Command, proposalId uint64) (*api.SecurityCanExecuteProposalResponse, error) { @@ -80,7 +79,7 @@ func canExecuteProposal(c *cli.Command, proposalId uint64) (*api.SecurityCanExec } -func executeProposal(c *cli.Command, proposalId uint64) (*api.SecurityExecuteProposalResponse, error) { +func executeProposal(c *cli.Command, proposalId uint64, opts *bind.TransactOpts) (*api.SecurityExecuteProposalResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -89,10 +88,6 @@ func executeProposal(c *cli.Command, proposalId uint64) (*api.SecurityExecutePro if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -101,18 +96,6 @@ func executeProposal(c *cli.Command, proposalId uint64) (*api.SecurityExecutePro // Response response := api.SecurityExecuteProposalResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Cancel proposal hash, err := security.ExecuteProposal(rp, proposalId, opts) if err != nil { diff --git a/rocketpool/api/security/join.go b/rocketpool/api/security/join.go index 6e785a008..cd9422065 100644 --- a/rocketpool/api/security/join.go +++ b/rocketpool/api/security/join.go @@ -1,7 +1,7 @@ package security import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao/security" "github.com/urfave/cli/v3" @@ -9,7 +9,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canJoin(c *cli.Command) (*api.SecurityCanJoinResponse, error) { @@ -80,16 +79,12 @@ func canJoin(c *cli.Command) (*api.SecurityCanJoinResponse, error) { } -func join(c *cli.Command) (*api.SecurityJoinResponse, error) { +func join(c *cli.Command, opts *bind.TransactOpts) (*api.SecurityJoinResponse, error) { // Get services if err := services.RequireNodeRegistered(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -99,14 +94,6 @@ func join(c *cli.Command) (*api.SecurityJoinResponse, error) { response := api.SecurityJoinResponse{} // Join - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } hash, err := security.Join(rp, opts) if err != nil { return nil, err diff --git a/rocketpool/api/security/leave.go b/rocketpool/api/security/leave.go index 3ce339ba8..8db9737c1 100644 --- a/rocketpool/api/security/leave.go +++ b/rocketpool/api/security/leave.go @@ -1,7 +1,7 @@ package security import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao/security" "github.com/urfave/cli/v3" @@ -9,7 +9,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canLeave(c *cli.Command) (*api.SecurityCanLeaveResponse, error) { @@ -70,16 +69,12 @@ func canLeave(c *cli.Command) (*api.SecurityCanLeaveResponse, error) { } -func leave(c *cli.Command) (*api.SecurityLeaveResponse, error) { +func leave(c *cli.Command, opts *bind.TransactOpts) (*api.SecurityLeaveResponse, error) { // Get services if err := services.RequireNodeSecurityMember(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -88,18 +83,6 @@ func leave(c *cli.Command) (*api.SecurityLeaveResponse, error) { // Response response := api.SecurityLeaveResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Leave hash, err := security.Leave(rp, opts) if err != nil { diff --git a/rocketpool/api/security/propose-leave.go b/rocketpool/api/security/propose-leave.go index 35d5c2c34..bc4fe3061 100644 --- a/rocketpool/api/security/propose-leave.go +++ b/rocketpool/api/security/propose-leave.go @@ -1,14 +1,13 @@ package security import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao/security" "github.com/urfave/cli/v3" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canProposeLeave(c *cli.Command) (*api.SecurityCanProposeLeaveResponse, error) { @@ -64,16 +63,12 @@ func canProposeLeave(c *cli.Command) (*api.SecurityCanProposeLeaveResponse, erro } -func proposeLeave(c *cli.Command) (*api.SecurityProposeLeaveResponse, error) { +func proposeLeave(c *cli.Command, opts *bind.TransactOpts) (*api.SecurityProposeLeaveResponse, error) { // Get services if err := services.RequireNodeSecurityMember(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -82,18 +77,6 @@ func proposeLeave(c *cli.Command) (*api.SecurityProposeLeaveResponse, error) { // Response response := api.SecurityProposeLeaveResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit proposal hash, err := security.RequestLeave(rp, opts) if err != nil { diff --git a/rocketpool/api/security/propose-settings.go b/rocketpool/api/security/propose-settings.go index 405aeb7e8..3b44f2871 100644 --- a/rocketpool/api/security/propose-settings.go +++ b/rocketpool/api/security/propose-settings.go @@ -3,6 +3,7 @@ package security import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/rocket-pool/smartnode/bindings/rocketpool" "github.com/rocket-pool/smartnode/bindings/settings/protocol" @@ -10,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" - "github.com/rocket-pool/smartnode/shared/utils/eth1" "github.com/urfave/cli/v3" ) @@ -215,7 +215,7 @@ func canProposeSetting(c *cli.Command, contractName string, settingName string, } -func proposeSetting(c *cli.Command, contractName string, settingName string, value string) (*api.ProposePDAOSettingResponse, error) { +func proposeSetting(c *cli.Command, contractName string, settingName string, value string, opts *bind.TransactOpts) (*api.ProposePDAOSettingResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -224,10 +224,6 @@ func proposeSetting(c *cli.Command, contractName string, settingName string, val if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -236,18 +232,6 @@ func proposeSetting(c *cli.Command, contractName string, settingName string, val // Response response := api.ProposePDAOSettingResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Submit the proposal var proposalID uint64 var hash common.Hash diff --git a/rocketpool/api/security/routes.go b/rocketpool/api/security/routes.go new file mode 100644 index 000000000..2446a17ef --- /dev/null +++ b/rocketpool/api/security/routes.go @@ -0,0 +1,189 @@ +package security + +import ( + "net/http" + "strconv" + + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/shared/services" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +// RegisterRoutes registers the security module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/security/status", func(w http.ResponseWriter, r *http.Request) { + resp, err := getStatus(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/members", func(w http.ResponseWriter, r *http.Request) { + resp, err := getMembers(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/proposals", func(w http.ResponseWriter, r *http.Request) { + resp, err := getProposals(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/proposal-details", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := getProposal(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/can-propose-leave", func(w http.ResponseWriter, r *http.Request) { + resp, err := canProposeLeave(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/propose-leave", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeLeave(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/can-propose-setting", func(w http.ResponseWriter, r *http.Request) { + contractName := r.URL.Query().Get("contractName") + settingName := r.URL.Query().Get("settingName") + value := r.URL.Query().Get("value") + resp, err := canProposeSetting(c, contractName, settingName, value) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/propose-setting", func(w http.ResponseWriter, r *http.Request) { + contractName := r.FormValue("contractName") + settingName := r.FormValue("settingName") + value := r.FormValue("value") + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := proposeSetting(c, contractName, settingName, value, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/can-cancel-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canCancelProposal(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/cancel-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := cancelProposal(c, id, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/can-vote-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canVoteOnProposal(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/vote-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + support := r.FormValue("support") == "true" + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := voteOnProposal(c, id, support, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/can-execute-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := canExecuteProposal(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/execute-proposal", func(w http.ResponseWriter, r *http.Request) { + id, err := parseUint64(r, "id") + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := executeProposal(c, id, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/can-join", func(w http.ResponseWriter, r *http.Request) { + resp, err := canJoin(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/join", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := join(c, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/can-leave", func(w http.ResponseWriter, r *http.Request) { + resp, err := canLeave(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/security/leave", func(w http.ResponseWriter, r *http.Request) { + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := leave(c, opts) + apiutils.WriteResponse(w, resp, err) + }) +} + +func parseUint64(r *http.Request, name string) (uint64, error) { + raw := r.URL.Query().Get(name) + if raw == "" { + raw = r.FormValue(name) + } + return strconv.ParseUint(raw, 10, 64) +} diff --git a/rocketpool/api/security/vote-proposal.go b/rocketpool/api/security/vote-proposal.go index 21fa354e2..54b097fbe 100644 --- a/rocketpool/api/security/vote-proposal.go +++ b/rocketpool/api/security/vote-proposal.go @@ -1,7 +1,7 @@ package security import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao" "github.com/rocket-pool/smartnode/bindings/dao/security" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canVoteOnProposal(c *cli.Command, proposalId uint64) (*api.SecurityCanVoteOnProposalResponse, error) { @@ -111,16 +110,12 @@ func canVoteOnProposal(c *cli.Command, proposalId uint64) (*api.SecurityCanVoteO } -func voteOnProposal(c *cli.Command, proposalId uint64, support bool) (*api.SecurityVoteOnProposalResponse, error) { +func voteOnProposal(c *cli.Command, proposalId uint64, support bool, opts *bind.TransactOpts) (*api.SecurityVoteOnProposalResponse, error) { // Get services if err := services.RequireNodeSecurityMember(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -129,18 +124,6 @@ func voteOnProposal(c *cli.Command, proposalId uint64, support bool) (*api.Secur // Response response := api.SecurityVoteOnProposalResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Vote on proposal hash, err := security.VoteOnProposal(rp, proposalId, support, opts) if err != nil { diff --git a/rocketpool/api/service/commands.go b/rocketpool/api/service/commands.go deleted file mode 100644 index fa2010e60..000000000 --- a/rocketpool/api/service/commands.go +++ /dev/null @@ -1,90 +0,0 @@ -package service - -import ( - "context" - - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage the Rocket Pool deposit queue", - Commands: []*cli.Command{ - { - Name: "get-gas-price-from-latest-block", - Aliases: []string{"g"}, - Usage: "Get the gas price from the latest block", - UsageText: "rocketpool api gas get-gas-price-from-latest-block", - Action: func(ctx context.Context, c *cli.Command) error { - - // Run - api.PrintResponse(getGasPriceFromLatestBlock(c)) - return nil - - }, - }, - - { - Name: "terminate-data-folder", - Aliases: []string{"t"}, - Usage: "Deletes the data folder including the wallet file, password file, and all validator keys - don't use this unless you have a very good reason to do it (such as switching from a Testnet to Mainnet)", - UsageText: "rocketpool api service terminate-data-folder", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(terminateDataFolder(c)) - return nil - - }, - }, - - { - Name: "get-client-status", - Aliases: []string{"g"}, - Usage: "Gets the status of the configured Execution and Beacon clients", - UsageText: "rocketpool api service get-client-status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getClientStatus(c)) - return nil - - }, - }, - - { - Name: "restart-vc", - Usage: "Restarts the validator client", - UsageText: "rocketpool api service restart-vc", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(restartVc(c)) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/service/routes.go b/rocketpool/api/service/routes.go new file mode 100644 index 000000000..ca9c2bbb7 --- /dev/null +++ b/rocketpool/api/service/routes.go @@ -0,0 +1,32 @@ +package service + +import ( + "net/http" + + "github.com/urfave/cli/v3" + + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +// RegisterRoutes registers the service module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/service/get-client-status", func(w http.ResponseWriter, r *http.Request) { + resp, err := getClientStatus(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/service/restart-vc", func(w http.ResponseWriter, r *http.Request) { + resp, err := restartVc(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/service/terminate-data-folder", func(w http.ResponseWriter, r *http.Request) { + resp, err := terminateDataFolder(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/service/get-gas-price-from-latest-block", func(w http.ResponseWriter, r *http.Request) { + resp, err := getGasPriceFromLatestBlock(c) + apiutils.WriteResponse(w, resp, err) + }) +} diff --git a/rocketpool/api/upgrade/commands.go b/rocketpool/api/upgrade/commands.go deleted file mode 100644 index 5e8868018..000000000 --- a/rocketpool/api/upgrade/commands.go +++ /dev/null @@ -1,74 +0,0 @@ -package upgrade - -import ( - "context" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" - "github.com/urfave/cli/v3" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage the Rocket Pool trusted node DAO upgrades", - Commands: []*cli.Command{ - { - Name: "get-upgrade-proposals", - Usage: "List the available upgrades", - UsageText: "rocketpool api upgrades get-upgrade-proposals", - Action: func(ctx context.Context, c *cli.Command) error { - // Run - api.PrintResponse(getUpgradeProposals(c)) - return nil - }, - }, - { - - Name: "can-execute-upgrade", - Usage: "Check whether the node can execute a proposal", - UsageText: "rocketpool api upgrades can-execute-upgrade upgrade-proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - upgradeProposalId, err := cliutils.ValidatePositiveUint("upgrade proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(canExecuteUpgrade(c, upgradeProposalId)) - return nil - - }, - }, - { - Name: "execute-upgrade", - Aliases: []string{"x"}, - Usage: "Execute an upgrade", - UsageText: "rocketpool api upgrades execute-upgrade upgrade-proposal-id", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - upgradeProposalId, err := cliutils.ValidatePositiveUint("upgrade proposal ID", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(executeUpgrade(c, upgradeProposalId)) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/upgrade/execute-upgrade.go b/rocketpool/api/upgrade/execute-upgrade.go index 8c745e0b5..fde627447 100644 --- a/rocketpool/api/upgrade/execute-upgrade.go +++ b/rocketpool/api/upgrade/execute-upgrade.go @@ -1,7 +1,7 @@ package upgrade import ( - "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/dao/trustednode" "github.com/rocket-pool/smartnode/bindings/dao/upgrades" @@ -11,7 +11,6 @@ import ( "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" - "github.com/rocket-pool/smartnode/shared/utils/eth1" ) func canExecuteUpgrade(c *cli.Command, upgradeProposalId uint64) (*api.CanExecuteTNDAOUpgradeResponse, error) { @@ -94,7 +93,7 @@ func canExecuteUpgrade(c *cli.Command, upgradeProposalId uint64) (*api.CanExecut } -func executeUpgrade(c *cli.Command, upgradeProposalId uint64) (*api.ExecuteTNDAOUpgradeResponse, error) { +func executeUpgrade(c *cli.Command, upgradeProposalId uint64, opts *bind.TransactOpts) (*api.ExecuteTNDAOUpgradeResponse, error) { // Get services if err := services.RequireNodeWallet(c); err != nil { @@ -103,10 +102,6 @@ func executeUpgrade(c *cli.Command, upgradeProposalId uint64) (*api.ExecuteTNDAO if err := services.RequireRocketStorage(c); err != nil { return nil, err } - w, err := services.GetWallet(c) - if err != nil { - return nil, err - } rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -115,18 +110,6 @@ func executeUpgrade(c *cli.Command, upgradeProposalId uint64) (*api.ExecuteTNDAO // Response response := api.ExecuteTNDAOUpgradeResponse{} - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - - // Override the provided pending TX if requested - err = eth1.CheckForNonceOverride(c, opts) - if err != nil { - return nil, fmt.Errorf("Error checking for nonce override: %w", err) - } - // Execute upgrade hash, err := upgrades.ExecuteUpgrade(rp, upgradeProposalId, opts) if err != nil { diff --git a/rocketpool/api/upgrade/routes.go b/rocketpool/api/upgrade/routes.go new file mode 100644 index 000000000..4eb0912ce --- /dev/null +++ b/rocketpool/api/upgrade/routes.go @@ -0,0 +1,45 @@ +package upgrade + +import ( + "net/http" + "strconv" + + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/shared/services" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" + cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" +) + +// RegisterRoutes registers the upgrade module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/upgrade/get-upgrade-proposals", func(w http.ResponseWriter, r *http.Request) { + resp, err := getUpgradeProposals(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/upgrade/can-execute-upgrade", func(w http.ResponseWriter, r *http.Request) { + id, err := cliutils.ValidatePositiveUint("upgrade proposal ID", r.URL.Query().Get("id")) + if err != nil { + apiutils.WriteResponse(w, nil, err) + return + } + resp, err := canExecuteUpgrade(c, id) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/upgrade/execute-upgrade", func(w http.ResponseWriter, r *http.Request) { + id, err := strconv.ParseUint(r.URL.Query().Get("id"), 10, 64) + if err != nil { + apiutils.WriteResponse(w, nil, err) + return + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := executeUpgrade(c, id, opts) + apiutils.WriteResponse(w, resp, err) + }) +} diff --git a/rocketpool/api/version.go b/rocketpool/api/version.go new file mode 100644 index 000000000..832e68741 --- /dev/null +++ b/rocketpool/api/version.go @@ -0,0 +1,22 @@ +package api + +import ( + "net/http" + + "github.com/rocket-pool/smartnode/shared" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +type VersionResponse struct { + Status string `json:"status"` + Error string `json:"error"` + Version string `json:"version"` +} + +// RegisterVersionRoute registers the /api/version endpoint on mux. +func RegisterVersionRoute(mux *http.ServeMux) { + mux.HandleFunc("/api/version", func(w http.ResponseWriter, r *http.Request) { + response := VersionResponse{Version: shared.RocketPoolVersion()} + apiutils.WriteResponse(w, &response, nil) + }) +} diff --git a/rocketpool/api/wait.go b/rocketpool/api/wait.go new file mode 100644 index 000000000..0dc873a80 --- /dev/null +++ b/rocketpool/api/wait.go @@ -0,0 +1,29 @@ +package api + +import ( + "net/http" + + "github.com/ethereum/go-ethereum/common" + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/bindings/utils" + "github.com/rocket-pool/smartnode/shared/services" + apitypes "github.com/rocket-pool/smartnode/shared/types/api" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +// RegisterWaitRoute registers the /api/wait endpoint on mux. +// It waits for a transaction hash to be mined. +func RegisterWaitRoute(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/wait", func(w http.ResponseWriter, r *http.Request) { + hash := common.HexToHash(r.URL.Query().Get("txHash")) + rp, err := services.GetRocketPool(c) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + response := apitypes.APIResponse{} + _, err = utils.WaitForTransactionWithContext(r.Context(), rp.Client, hash) + apiutils.WriteResponse(w, &response, err) + }) +} diff --git a/rocketpool/api/wallet/commands.go b/rocketpool/api/wallet/commands.go deleted file mode 100644 index c1d209863..000000000 --- a/rocketpool/api/wallet/commands.go +++ /dev/null @@ -1,353 +0,0 @@ -package wallet - -import ( - "context" - - "github.com/urfave/cli/v3" - - "github.com/rocket-pool/smartnode/shared/utils/api" - cliutils "github.com/rocket-pool/smartnode/shared/utils/cli" -) - -// Register subcommands -func RegisterSubcommands(command *cli.Command, name string, aliases []string) { - command.Commands = append(command.Commands, &cli.Command{ - Name: name, - Aliases: aliases, - Usage: "Manage the node wallet", - Commands: []*cli.Command{ - - { - Name: "status", - Aliases: []string{"s"}, - Usage: "Get the node wallet status", - UsageText: "rocketpool api wallet status", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(getStatus(c)) - return nil - - }, - }, - - { - Name: "set-password", - Aliases: []string{"p"}, - Usage: "Set the node wallet password", - UsageText: "rocketpool api wallet set-password password", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - password, err := cliutils.ValidateNodePassword("wallet password", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(setPassword(c, password)) - return nil - - }, - }, - - { - Name: "init", - Aliases: []string{"i"}, - Usage: "Initialize the node wallet", - UsageText: "rocketpool api wallet init", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "derivation-path", - Aliases: []string{"d"}, - Usage: "Specify the derivation path for the wallet.\nOmit this flag (or leave it blank) for the default of \"m/44'/60'/0'/0/%d\" (where %d is the index).\nSet this to \"ledgerLive\" to use Ledger Live's path of \"m/44'/60'/%d/0/0\".\nSet this to \"mew\" to use MyEtherWallet's path of \"m/44'/60'/0'/%d\".\nFor custom paths, simply enter them here.", - }, - }, - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(initWallet(c)) - return nil - - }, - }, - - { - Name: "recover", - Aliases: []string{"r"}, - Usage: "Recover a node wallet from a mnemonic phrase", - UsageText: "rocketpool api wallet recover mnemonic", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "skip-validator-key-recovery", - Aliases: []string{"k"}, - Usage: "Recover the node wallet, but do not regenerate its validator keys", - }, - &cli.StringFlag{ - Name: "derivation-path", - Aliases: []string{"d"}, - Usage: "Specify the derivation path for the wallet.\nOmit this flag (or leave it blank) for the default of \"m/44'/60'/0'/0/%d\" (where %d is the index).\nSet this to \"ledgerLive\" to use Ledger Live's path of \"m/44'/60'/%d/0/0\".\nSet this to \"mew\" to use MyEtherWallet's path of \"m/44'/60'/0'/%d\".\nFor custom paths, simply enter them here.", - }, - &cli.Uint64Flag{ - Name: "wallet-index", - Aliases: []string{"i"}, - Usage: "Specify the index to use with the derivation path when recovering your wallet", - Value: 0, - }, - }, - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - mnemonic, err := cliutils.ValidateWalletMnemonic("mnemonic", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(recoverWallet(c, mnemonic)) - return nil - - }, - }, - - { - Name: "search-and-recover", - Aliases: []string{"r"}, - Usage: "Search for and recover a node wallet's derivation key and index using a mnemonic phrase and a well-known address.", - UsageText: "rocketpool api wallet search-and-recover mnemonic address", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "skip-validator-key-recovery", - Aliases: []string{"k"}, - Usage: "Recover the node wallet, but do not regenerate its validator keys", - }, - }, - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - mnemonic, err := cliutils.ValidateWalletMnemonic("mnemonic", c.Args().Get(0)) - if err != nil { - return err - } - address, err := cliutils.ValidateAddress("address", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(searchAndRecoverWallet(c, mnemonic, address)) - return nil - - }, - }, - - { - Name: "rebuild", - Aliases: []string{"b"}, - Usage: "Rebuild validator keystores from derived keys", - UsageText: "rocketpool api wallet rebuild", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(rebuildWallet(c)) - return nil - - }, - }, - - { - Name: "test-recovery", - Aliases: []string{"r"}, - Usage: "Test recovery of a node wallet and its validator keys without actually saving the recovered files", - UsageText: "rocketpool api wallet test-recovery mnemonic", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "skip-validator-key-recovery", - Aliases: []string{"k"}, - Usage: "Recover the node wallet, but do not regenerate its validator keys", - }, - &cli.StringFlag{ - Name: "derivation-path", - Aliases: []string{"d"}, - Usage: "Specify the derivation path for the wallet.\nOmit this flag (or leave it blank) for the default of \"m/44'/60'/0'/0/%d\" (where %d is the index).\nSet this to \"ledgerLive\" to use Ledger Live's path of \"m/44'/60'/%d/0/0\".\nSet this to \"mew\" to use MyEtherWallet's path of \"m/44'/60'/0'/%d\".\nFor custom paths, simply enter them here.", - }, - &cli.Uint64Flag{ - Name: "wallet-index", - Aliases: []string{"i"}, - Usage: "Specify the index to use with the derivation path when recovering your wallet", - Value: 0, - }, - }, - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - mnemonic, err := cliutils.ValidateWalletMnemonic("mnemonic", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(testRecoverWallet(c, mnemonic)) - return nil - - }, - }, - - { - Name: "test-search-and-recover", - Aliases: []string{"r"}, - Usage: "Test searching for and recovery of a node wallet's derivation key, index, and validator keys using a mnemonic phrase and a well-known address.", - UsageText: "rocketpool api wallet test-search-and-recover mnemonic address", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "skip-validator-key-recovery", - Aliases: []string{"k"}, - Usage: "Recover the node wallet, but do not regenerate its validator keys", - }, - }, - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 2); err != nil { - return err - } - mnemonic, err := cliutils.ValidateWalletMnemonic("mnemonic", c.Args().Get(0)) - if err != nil { - return err - } - address, err := cliutils.ValidateAddress("address", c.Args().Get(1)) - if err != nil { - return err - } - - // Run - api.PrintResponse(testSearchAndRecoverWallet(c, mnemonic, address)) - return nil - - }, - }, - - { - Name: "export", - Aliases: []string{"e"}, - Usage: "Export the node wallet in JSON format", - UsageText: "rocketpool api wallet export", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(exportWallet(c)) - return nil - - }, - }, - - { - Name: "estimate-gas-set-ens-name", - Usage: "Estimate the gas required to set the name for the node wallet's ENS reverse record", - UsageText: "rocketpool api node estimate-gas-set-ens-name name", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Run - api.PrintResponse(setEnsName(c, c.Args().Get(0), true)) - return nil - - }, - }, - - { - Name: "set-ens-name", - Usage: "Set a name to the node wallet's ENS reverse record", - UsageText: "rocketpool api node set-ens-name name", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - - // Run - api.PrintResponse(setEnsName(c, c.Args().Get(0), false)) - return nil - - }, - }, - - { - Name: "masquerade", - Usage: "Change your node's effective address to a different one. Your node will not be able to submit transactions or sign messages since you don't have the corresponding wallet's private key.", - UsageText: "rocketpool api wallet masquerade address", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 1); err != nil { - return err - } - address, err := cliutils.ValidateAddress("address", c.Args().Get(0)) - if err != nil { - return err - } - - // Run - api.PrintResponse(masquerade(c, address)) - return nil - - }, - }, - - { - Name: "end-masquerade", - Usage: "End a masquerade, restoring your node's effective address back to your wallet address if one is loaded.", - UsageText: "rocketpool api wallet end-masquerade", - Action: func(ctx context.Context, c *cli.Command) error { - - // Validate args - if err := cliutils.ValidateArgCount(c, 0); err != nil { - return err - } - - // Run - api.PrintResponse(endMasquerade(c)) - return nil - - }, - }, - }, - }) -} diff --git a/rocketpool/api/wallet/ens-name.go b/rocketpool/api/wallet/ens-name.go index a36fb0308..6dc147ca7 100644 --- a/rocketpool/api/wallet/ens-name.go +++ b/rocketpool/api/wallet/ens-name.go @@ -3,6 +3,7 @@ package wallet import ( "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/rocket-pool/smartnode/bindings/rocketpool" "github.com/rocket-pool/smartnode/shared/services" "github.com/rocket-pool/smartnode/shared/types/api" @@ -16,7 +17,7 @@ const ( ) // Set a name to the node wallet's ENS reverse record. -func setEnsName(c *cli.Command, name string, onlyEstimateGas bool) (*api.SetEnsNameResponse, error) { +func setEnsName(c *cli.Command, name string, onlyEstimateGas bool, opts *bind.TransactOpts) (*api.SetEnsNameResponse, error) { rp, err := services.GetRocketPool(c) if err != nil { return nil, err @@ -54,12 +55,6 @@ func setEnsName(c *cli.Command, name string, onlyEstimateGas bool) (*api.SetEnsN return nil, fmt.Errorf("error: the ENS record already points to the name '%s'", name) } - // Get transactor - opts, err := w.GetNodeAccountTransactor() - if err != nil { - return nil, err - } - // If onlyEstimateGas is set, then don't send the tx, only simulates and returns the gas estimate opts.NoSend = onlyEstimateGas diff --git a/rocketpool/api/wallet/init.go b/rocketpool/api/wallet/init.go index 70bf5d4bf..19bd1167c 100644 --- a/rocketpool/api/wallet/init.go +++ b/rocketpool/api/wallet/init.go @@ -11,6 +11,10 @@ import ( ) func initWallet(c *cli.Command) (*api.InitWalletResponse, error) { + return initWalletWithPath(c, c.String("derivation-path")) +} + +func initWalletWithPath(c *cli.Command, derivationPath string) (*api.InitWalletResponse, error) { // Get services w, err := services.GetWallet(c) @@ -27,7 +31,7 @@ func initWallet(c *cli.Command) (*api.InitWalletResponse, error) { } // Get the derivation path - path := c.String("derivation-path") + path := derivationPath switch path { case "": path = wallet.DefaultNodeKeyPath diff --git a/rocketpool/api/wallet/recover.go b/rocketpool/api/wallet/recover.go index d7622732c..5bfee2262 100644 --- a/rocketpool/api/wallet/recover.go +++ b/rocketpool/api/wallet/recover.go @@ -19,6 +19,10 @@ const ( ) func recoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletResponse, error) { + return recoverWalletWithParams(c, mnemonic, c.Bool("skip-validator-key-recovery"), c.String("derivation-path"), c.Uint("wallet-index")) +} + +func recoverWalletWithParams(c *cli.Command, mnemonic string, skipValidatorKeyRecovery bool, derivationPath string, walletIndex uint) (*api.RecoverWalletResponse, error) { // Get services w, err := services.GetWallet(c) @@ -26,7 +30,7 @@ func recoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletResponse, return nil, err } var rp *rocketpool.RocketPool - if !c.Bool("skip-validator-key-recovery") { + if !skipValidatorKeyRecovery { if err := services.RequireRocketStorage(c); err != nil { return nil, err } @@ -49,7 +53,7 @@ func recoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletResponse, } // Get the derivation path - path := c.String("derivation-path") + path := derivationPath switch path { case "": path = wallet.DefaultNodeKeyPath @@ -59,9 +63,6 @@ func recoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletResponse, path = wallet.MyEtherWalletNodeKeyPath } - // Get the wallet index - walletIndex := c.Uint("wallet-index") - // Recover wallet if err := w.Recover(path, walletIndex, mnemonic); err != nil { return nil, err @@ -74,7 +75,7 @@ func recoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletResponse, } response.AccountAddress = nodeAccount.Address - if !c.Bool("skip-validator-key-recovery") { + if !skipValidatorKeyRecovery { response.ValidatorKeys, err = walletutils.RecoverNodeKeys(c, rp, bc, nodeAccount.Address, w, false) if err != nil { return nil, err @@ -92,6 +93,10 @@ func recoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletResponse, } func searchAndRecoverWallet(c *cli.Command, mnemonic string, address common.Address) (*api.SearchAndRecoverWalletResponse, error) { + return searchAndRecoverWalletWithParams(c, mnemonic, address, c.Bool("skip-validator-key-recovery")) +} + +func searchAndRecoverWalletWithParams(c *cli.Command, mnemonic string, address common.Address, skipValidatorKeyRecovery bool) (*api.SearchAndRecoverWalletResponse, error) { // Get services w, err := services.GetWallet(c) @@ -99,7 +104,7 @@ func searchAndRecoverWallet(c *cli.Command, mnemonic string, address common.Addr return nil, err } var rp *rocketpool.RocketPool - if !c.Bool("skip-validator-key-recovery") { + if !skipValidatorKeyRecovery { if err := services.RequireRocketStorage(c); err != nil { return nil, err } @@ -173,7 +178,7 @@ func searchAndRecoverWallet(c *cli.Command, mnemonic string, address common.Addr } response.AccountAddress = nodeAccount.Address - if !c.Bool("skip-validator-key-recovery") { + if !skipValidatorKeyRecovery { response.ValidatorKeys, err = walletutils.RecoverNodeKeys(c, rp, bc, nodeAccount.Address, w, false) if err != nil { return nil, err diff --git a/rocketpool/api/wallet/routes.go b/rocketpool/api/wallet/routes.go new file mode 100644 index 000000000..3d8059935 --- /dev/null +++ b/rocketpool/api/wallet/routes.go @@ -0,0 +1,115 @@ +package wallet + +import ( + "net/http" + "strconv" + + "github.com/ethereum/go-ethereum/common" + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/shared/services" + apiutils "github.com/rocket-pool/smartnode/shared/utils/api" +) + +// RegisterRoutes registers the wallet module's HTTP routes onto mux. +func RegisterRoutes(mux *http.ServeMux, c *cli.Command) { + mux.HandleFunc("/api/wallet/status", func(w http.ResponseWriter, r *http.Request) { + resp, err := getStatus(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/set-password", func(w http.ResponseWriter, r *http.Request) { + password := r.FormValue("password") + resp, err := setPassword(c, password) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/init", func(w http.ResponseWriter, r *http.Request) { + derivationPath := r.URL.Query().Get("derivationPath") + if derivationPath == "" { + derivationPath = r.FormValue("derivationPath") + } + resp, err := initWalletWithPath(c, derivationPath) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/recover", func(w http.ResponseWriter, r *http.Request) { + mnemonic := r.FormValue("mnemonic") + skipRecovery := r.FormValue("skipValidatorKeyRecovery") == "true" + derivationPath := r.FormValue("derivationPath") + walletIndex, _ := strconv.ParseUint(r.FormValue("walletIndex"), 10, 64) + resp, err := recoverWalletWithParams(c, mnemonic, skipRecovery, derivationPath, uint(walletIndex)) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/search-and-recover", func(w http.ResponseWriter, r *http.Request) { + mnemonic := r.FormValue("mnemonic") + address := common.HexToAddress(r.FormValue("address")) + skipRecovery := r.FormValue("skipValidatorKeyRecovery") == "true" + resp, err := searchAndRecoverWalletWithParams(c, mnemonic, address, skipRecovery) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/test-recover", func(w http.ResponseWriter, r *http.Request) { + mnemonic := r.FormValue("mnemonic") + skipRecovery := r.FormValue("skipValidatorKeyRecovery") == "true" + derivationPath := r.FormValue("derivationPath") + walletIndex, _ := strconv.ParseUint(r.FormValue("walletIndex"), 10, 64) + resp, err := testRecoverWalletWithParams(c, mnemonic, skipRecovery, derivationPath, uint(walletIndex)) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/test-search-and-recover", func(w http.ResponseWriter, r *http.Request) { + mnemonic := r.FormValue("mnemonic") + address := common.HexToAddress(r.FormValue("address")) + skipRecovery := r.FormValue("skipValidatorKeyRecovery") == "true" + resp, err := testSearchAndRecoverWalletWithParams(c, mnemonic, address, skipRecovery) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/rebuild", func(w http.ResponseWriter, r *http.Request) { + resp, err := rebuildWallet(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/export", func(w http.ResponseWriter, r *http.Request) { + resp, err := exportWallet(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/masquerade", func(w http.ResponseWriter, r *http.Request) { + address := common.HexToAddress(r.FormValue("address")) + resp, err := masquerade(c, address) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/end-masquerade", func(w http.ResponseWriter, r *http.Request) { + resp, err := endMasquerade(c) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/estimate-gas-set-ens-name", func(w http.ResponseWriter, r *http.Request) { + name := r.URL.Query().Get("name") + if name == "" { + name = r.FormValue("name") + } + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setEnsName(c, name, true, opts) + apiutils.WriteResponse(w, resp, err) + }) + + mux.HandleFunc("/api/wallet/set-ens-name", func(w http.ResponseWriter, r *http.Request) { + name := r.FormValue("name") + opts, err := services.GetNodeAccountTransactorFromRequest(c, r) + if err != nil { + apiutils.WriteErrorResponse(w, err) + return + } + resp, err := setEnsName(c, name, false, opts) + apiutils.WriteResponse(w, resp, err) + }) +} diff --git a/rocketpool/api/wallet/test.go b/rocketpool/api/wallet/test.go index ce124c5cc..639e819aa 100644 --- a/rocketpool/api/wallet/test.go +++ b/rocketpool/api/wallet/test.go @@ -14,6 +14,10 @@ import ( ) func testRecoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletResponse, error) { + return testRecoverWalletWithParams(c, mnemonic, c.Bool("skip-validator-key-recovery"), c.String("derivation-path"), c.Uint("wallet-index")) +} + +func testRecoverWalletWithParams(c *cli.Command, mnemonic string, skipValidatorKeyRecovery bool, derivationPath string, walletIndex uint) (*api.RecoverWalletResponse, error) { // Get services cfg, err := services.GetConfig(c) @@ -21,7 +25,7 @@ func testRecoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletRespo return nil, err } var rp *rocketpool.RocketPool - if !c.Bool("skip-validator-key-recovery") { + if !skipValidatorKeyRecovery { if err := services.RequireRocketStorage(c); err != nil { return nil, err } @@ -47,7 +51,7 @@ func testRecoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletRespo response := api.RecoverWalletResponse{} // Get the derivation path - path := c.String("derivation-path") + path := derivationPath switch path { case "": path = wallet.DefaultNodeKeyPath @@ -57,9 +61,6 @@ func testRecoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletRespo path = wallet.MyEtherWalletNodeKeyPath } - // Get the wallet index - walletIndex := c.Uint("wallet-index") - // Recover wallet if err := w.TestRecovery(path, walletIndex, mnemonic); err != nil { return nil, err @@ -72,7 +73,7 @@ func testRecoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletRespo } response.AccountAddress = nodeAccount.Address - if !c.Bool("skip-validator-key-recovery") { + if !skipValidatorKeyRecovery { response.ValidatorKeys, err = walletutils.RecoverNodeKeys(c, rp, bc, nodeAccount.Address, w, true) if err != nil { return nil, err @@ -85,6 +86,10 @@ func testRecoverWallet(c *cli.Command, mnemonic string) (*api.RecoverWalletRespo } func testSearchAndRecoverWallet(c *cli.Command, mnemonic string, address common.Address) (*api.SearchAndRecoverWalletResponse, error) { + return testSearchAndRecoverWalletWithParams(c, mnemonic, address, c.Bool("skip-validator-key-recovery")) +} + +func testSearchAndRecoverWalletWithParams(c *cli.Command, mnemonic string, address common.Address, skipValidatorKeyRecovery bool) (*api.SearchAndRecoverWalletResponse, error) { // Get services cfg, err := services.GetConfig(c) @@ -92,7 +97,7 @@ func testSearchAndRecoverWallet(c *cli.Command, mnemonic string, address common. return nil, err } var rp *rocketpool.RocketPool - if !c.Bool("skip-validator-key-recovery") { + if !skipValidatorKeyRecovery { if err := services.RequireRocketStorage(c); err != nil { return nil, err } @@ -169,7 +174,7 @@ func testSearchAndRecoverWallet(c *cli.Command, mnemonic string, address common. } response.AccountAddress = nodeAccount.Address - if !c.Bool("skip-validator-key-recovery") { + if !skipValidatorKeyRecovery { response.ValidatorKeys, err = walletutils.RecoverNodeKeys(c, rp, bc, nodeAccount.Address, w, true) if err != nil { return nil, err diff --git a/rocketpool/node/http.go b/rocketpool/node/http.go new file mode 100644 index 000000000..f6a62831f --- /dev/null +++ b/rocketpool/node/http.go @@ -0,0 +1,84 @@ +package node + +import ( + "context" + "fmt" + "log" + "net/http" + "time" + + "github.com/urfave/cli/v3" + + "github.com/rocket-pool/smartnode/rocketpool/node/routes" + "github.com/rocket-pool/smartnode/shared/services/config" +) + +type httpServer struct { + server *http.Server + mux *http.ServeMux +} + +// statusRecorder wraps http.ResponseWriter to capture the written status code. +type statusRecorder struct { + http.ResponseWriter + status int +} + +func (r *statusRecorder) WriteHeader(code int) { + r.status = code + r.ResponseWriter.WriteHeader(code) +} + +// Write implements the ResponseWriter interface so we don't lose the original +// Write behavior when wrapping. +func (r *statusRecorder) Write(b []byte) (int, error) { + return r.ResponseWriter.Write(b) +} + +// loggingMiddleware logs method, path, status code, and elapsed time for every request. +func loggingMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + rec := &statusRecorder{ResponseWriter: w, status: http.StatusOK} + next.ServeHTTP(rec, r) + log.Printf("%s %s %d %s", r.Method, r.URL.Path, rec.status, time.Since(start)) + }) +} + +// startHTTP starts the node's HTTP API server and returns immediately. +// The server runs in the background for the lifetime of the process. +func startHTTP(ctx context.Context, c *cli.Command, cfg *config.RocketPoolConfig) { + port, ok := cfg.Smartnode.APIPort.Value.(uint16) + if !ok || port == 0 { + log.Println("Warning: APIPort not configured, HTTP API server will not start.") + return + } + + var host string + if !cfg.IsNativeMode { + // In Docker mode the server must bind to 0.0.0.0, so other containers can reach it. + host = "0.0.0.0" + } else { + host = "127.0.0.1" + } + + mux := http.NewServeMux() + routes.RegisterRoutes(mux, c) + + srv := &http.Server{ + Addr: fmt.Sprintf("%s:%d", host, port), + Handler: loggingMiddleware(mux), + } + + go func() { + log.Printf("Node HTTP API server listening on %s:%d\n", host, port) + if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { + log.Printf("Node HTTP API server error: %v\n", err) + } + }() + + go func() { + <-ctx.Done() + _ = srv.Shutdown(context.Background()) + }() +} diff --git a/rocketpool/node/metrics-exporter.go b/rocketpool/node/metrics-exporter.go index ae53576a1..f9fb13f30 100644 --- a/rocketpool/node/metrics-exporter.go +++ b/rocketpool/node/metrics-exporter.go @@ -1,6 +1,7 @@ package node import ( + "context" "fmt" "net/http" "os" @@ -16,7 +17,7 @@ import ( "github.com/urfave/cli/v3" ) -func runMetricsServer(c *cli.Command, logger log.ColorLogger, stateLocker *collectors.StateLocker) error { +func runMetricsServer(ctx context.Context, c *cli.Command, logger log.ColorLogger, stateLocker *collectors.StateLocker) error { // Get services cfg, err := services.GetConfig(c) @@ -105,8 +106,9 @@ func runMetricsServer(c *cli.Command, logger log.ColorLogger, stateLocker *colle } logger.Printlnf("Starting metrics exporter on %s:%d.", metricsAddress, metricsPort) metricsPath := "/metrics" - http.Handle(metricsPath, handler) - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + mux := http.NewServeMux() + mux.Handle(metricsPath, handler) + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`