From 9223cd2715225a5f90f5ae0f62d202b446c00034 Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Tue, 17 Dec 2024 14:31:36 -0500 Subject: [PATCH 01/25] save stubs --- cli/commands/executeWithdrawal.go | 14 ++++++++++++++ cli/commands/queueWithdrawal.go | 19 +++++++++++++++++++ cli/commands/showWithdrawals.go | 8 ++++++++ cli/main.go | 17 +++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 cli/commands/executeWithdrawal.go create mode 100644 cli/commands/queueWithdrawal.go create mode 100644 cli/commands/showWithdrawals.go diff --git a/cli/commands/executeWithdrawal.go b/cli/commands/executeWithdrawal.go new file mode 100644 index 00000000..c8eb4be4 --- /dev/null +++ b/cli/commands/executeWithdrawal.go @@ -0,0 +1,14 @@ +package commands + +import "github.com/pkg/errors" + +func ExecuteWithdrawalCommand(args TComputeCheckpointableValueCommandArgs) error { + /* + TODO: IDelegationManager.completeQueuedWithdrawals( + IERC20[][] calldata tokens, + bool[] calldata receiveAsTokens, + uint256 numToComplete + ) + */ + return errors.New("unimplemented.") +} diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go new file mode 100644 index 00000000..a4a4257e --- /dev/null +++ b/cli/commands/queueWithdrawal.go @@ -0,0 +1,19 @@ +package commands + +import "github.com/pkg/errors" + +func QueueWithdrawalCommand(args TComputeCheckpointableValueCommandArgs) error { + // TODO: IDelegationManager.queueWithdrawals + /* + struct QueuedWithdrawalParams { + // Array of strategies that the QueuedWithdrawal contains + IStrategy[] strategies; + // Array containing the amount of depositShares for withdrawal in each Strategy in the `strategies` array + // Note that the actual shares received on completing withdrawal may be less than the depositShares if slashing occurred + uint256[] depositShares; + // The address of the withdrawer + address withdrawer; + } + */ + return errors.New("unimplemented.") +} diff --git a/cli/commands/showWithdrawals.go b/cli/commands/showWithdrawals.go new file mode 100644 index 00000000..4db157cd --- /dev/null +++ b/cli/commands/showWithdrawals.go @@ -0,0 +1,8 @@ +package commands + +import "github.com/pkg/errors" + +func ShowWithdrawalsCommand(args TComputeCheckpointableValueCommandArgs) error { + // IDelegationManager.getQueuedWithdrawals + return errors.New("unimplemented.") +} diff --git a/cli/main.go b/cli/main.go index 99fed8b2..09f8d79f 100644 --- a/cli/main.go +++ b/cli/main.go @@ -196,6 +196,23 @@ func main() { }) }, }, + { + Name: "queue-withdrawal", + Args: true, + Usage: "Queues a withdrawal ", + Flags: []cli.Flag{ + ExecNodeFlag, + BeaconNodeFlag, + PodAddressFlag, + }, + Action: func(_ *cli.Context) error { + return commands.QueueWithdrawalCommand(commands.TComputeCheckpointableValueCommandArgs{ + Node: node, + BeaconNode: beacon, + PodAddress: eigenpodAddress, + }) + }, + }, }, Flags: []cli.Flag{ &cli.BoolFlag{ From ab15d5ded9a7d488b1a6a682726429eac779601b Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Tue, 17 Dec 2024 15:11:01 -0500 Subject: [PATCH 02/25] save --- cli/commands/completeAllWithdrawals.go | 20 ++++++++++++ cli/commands/executeWithdrawal.go | 14 --------- cli/commands/queueWithdrawal.go | 8 ++++- cli/commands/showWithdrawals.go | 8 ++++- cli/main.go | 42 +++++++++++++++++++++++--- 5 files changed, 72 insertions(+), 20 deletions(-) create mode 100644 cli/commands/completeAllWithdrawals.go delete mode 100644 cli/commands/executeWithdrawal.go diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go new file mode 100644 index 00000000..b3a1fa0b --- /dev/null +++ b/cli/commands/completeAllWithdrawals.go @@ -0,0 +1,20 @@ +package commands + +import "github.com/pkg/errors" + +type TCompleteWithdrawalArgs struct { + EthNode string + BeaconNode string + EigenPod string +} + +func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { + /* + TODO: IDelegationManager.completeQueuedWithdrawals( + IERC20[][] calldata tokens, + bool[] calldata receiveAsTokens, + uint256 numToComplete + ) + */ + return errors.New("unimplemented.") +} diff --git a/cli/commands/executeWithdrawal.go b/cli/commands/executeWithdrawal.go deleted file mode 100644 index c8eb4be4..00000000 --- a/cli/commands/executeWithdrawal.go +++ /dev/null @@ -1,14 +0,0 @@ -package commands - -import "github.com/pkg/errors" - -func ExecuteWithdrawalCommand(args TComputeCheckpointableValueCommandArgs) error { - /* - TODO: IDelegationManager.completeQueuedWithdrawals( - IERC20[][] calldata tokens, - bool[] calldata receiveAsTokens, - uint256 numToComplete - ) - */ - return errors.New("unimplemented.") -} diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index a4a4257e..32698ae6 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -2,7 +2,13 @@ package commands import "github.com/pkg/errors" -func QueueWithdrawalCommand(args TComputeCheckpointableValueCommandArgs) error { +type TQueueWithdrawallArgs struct { + EthNode string + BeaconNode string + EigenPod string +} + +func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { // TODO: IDelegationManager.queueWithdrawals /* struct QueuedWithdrawalParams { diff --git a/cli/commands/showWithdrawals.go b/cli/commands/showWithdrawals.go index 4db157cd..e3ab5ce1 100644 --- a/cli/commands/showWithdrawals.go +++ b/cli/commands/showWithdrawals.go @@ -2,7 +2,13 @@ package commands import "github.com/pkg/errors" -func ShowWithdrawalsCommand(args TComputeCheckpointableValueCommandArgs) error { +type TShowWithdrawalArgs struct { + EthNode string + BeaconNode string + EigenPod string +} + +func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { // IDelegationManager.getQueuedWithdrawals return errors.New("unimplemented.") } diff --git a/cli/main.go b/cli/main.go index 09f8d79f..3194febc 100644 --- a/cli/main.go +++ b/cli/main.go @@ -196,20 +196,54 @@ func main() { }) }, }, + { + Name: "complete-all-withdrawals", + Args: true, + Usage: "Completes all withdrawals", + Flags: []cli.Flag{ + ExecNodeFlag, + BeaconNodeFlag, + PodAddressFlag, + }, + Action: func(_ *cli.Context) error { + return commands.CompleteAllWithdrawalsCommand(commands.TCompleteWithdrawalArgs{ + EthNode: node, + BeaconNode: beacon, + EigenPod: eigenpodAddress, + }) + }, + }, { Name: "queue-withdrawal", Args: true, - Usage: "Queues a withdrawal ", + Usage: "Queues a withdrawal", Flags: []cli.Flag{ ExecNodeFlag, BeaconNodeFlag, PodAddressFlag, }, Action: func(_ *cli.Context) error { - return commands.QueueWithdrawalCommand(commands.TComputeCheckpointableValueCommandArgs{ - Node: node, + return commands.QueueWithdrawalCommand(commands.TQueueWithdrawallArgs{ + EthNode: node, + BeaconNode: beacon, + EigenPod: eigenpodAddress, + }) + }, + }, + { + Name: "show-withdrawals", + Args: true, + Usage: "Shows all pending withdrawals", + Flags: []cli.Flag{ + ExecNodeFlag, + BeaconNodeFlag, + PodAddressFlag, + }, + Action: func(_ *cli.Context) error { + return commands.ShowWithdrawalsCommand(commands.TShowWithdrawalArgs{ + EthNode: node, BeaconNode: beacon, - PodAddress: eigenpodAddress, + EigenPod: eigenpodAddress, }) }, }, From 5922718f096728977ee1c2b4c78015cbea77b36a Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Tue, 17 Dec 2024 18:16:25 -0500 Subject: [PATCH 03/25] blocked on queued withdrawal helper --- cli/commands/completeAllWithdrawals.go | 113 +++++++++++++++++++++++-- cli/commands/queueWithdrawal.go | 17 +++- cli/commands/showWithdrawals.go | 71 +++++++++++++++- cli/flags.go | 9 ++ cli/main.go | 2 +- go.mod | 2 + go.sum | 2 + 7 files changed, 201 insertions(+), 15 deletions(-) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index b3a1fa0b..98481ba2 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -1,6 +1,17 @@ package commands -import "github.com/pkg/errors" +import ( + "context" + "fmt" + "math/big" + + . "github.com/samber/lo" + + "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" + "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/ethereum/go-ethereum/common" +) type TCompleteWithdrawalArgs struct { EthNode string @@ -8,13 +19,97 @@ type TCompleteWithdrawalArgs struct { EigenPod string } +func DelegationManager(chainId *big.Int) common.Address { + data := map[uint64]string{ + // TODO(zeus) - make this runnable via zeus. + 1: "0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A", // mainnet + 17000: "0x75dfE5B44C2E530568001400D3f704bC8AE350CC", // holesky preprod + } + contract, ok := data[chainId.Uint64()] + if !ok { + panic("no delegation manager found for chain") + } + addr := common.HexToAddress(contract) + return addr +} + func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { - /* - TODO: IDelegationManager.completeQueuedWithdrawals( - IERC20[][] calldata tokens, - bool[] calldata receiveAsTokens, - uint256 numToComplete - ) - */ - return errors.New("unimplemented.") + ctx := context.Background() + eth, _, chainId, err := core.GetClients(ctx, args.EthNode, args.BeaconNode, false /* isVerbose */) + curBlockNumber, err := eth.BlockNumber(nil) + + pod, err := EigenPod.NewEigenPod(common.HexToAddress(args.EigenPod), eth) + core.PanicOnError("failed to reach eigenpod", err) + + reg, err := pod.WithdrawableRestakedExecutionLayerGwei(nil) + core.PanicOnError("failed to fetch REG", err) + + podOwner, err := pod.PodOwner(nil) + core.PanicOnError("failed to read podOwner", err) + + delegationManager, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) + core.PanicOnError("failed to reach delegation manager", err) + + minDelay, err := delegationManager.MinWithdrawalDelayBlocks(nil) + core.PanicOnError("failed to read MinWithdrawalDelayBlocks", err) + + queuedWithdrawals, err := delegationManager.GetQueuedWithdrawals(nil, podOwner) + core.PanicOnError("failed to read queuedWithdrawals", err) + + beaconETHStrategy := common.HexToAddress("0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0") + + eligibleWithdrawals := Map(queuedWithdrawals.Withdrawals, func(withdrawal IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { + isBeaconWithdrawal := len(withdrawal.Strategies) == 1 && withdrawal.Strategies[0].Cmp(beaconETHStrategy) == 0 + isExecutable := curBlockNumber <= uint64(withdrawal.StartBlock+minDelay) + if isBeaconWithdrawal && isExecutable { + return &withdrawal + } + return nil + }) + + var runningSum uint64 = 0 + affordedWithdrawals := Map(eligibleWithdrawals, func(withdrawal *IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { + if withdrawal == nil { + return nil + } + withdrawalShares := queuedWithdrawals.Shares[index][0].Uint64() + if reg < (runningSum + withdrawalShares) { + runningSum = runningSum + withdrawalShares + return withdrawal + } + return nil + }) + + // filter out any nils. + affordedWithdrawals = Filter(affordedWithdrawals, func(withdrawal *IDelegationManager.IDelegationManagerTypesWithdrawal, index int) bool { + return withdrawal != nil + }) + + if len(affordedWithdrawals) != len(eligibleWithdrawals) { + fmt.Printf("WARN: Your pod has %d withdrawals available, but you only have enough balance to satisfy %d of them.\n", len(eligibleWithdrawals), len(affordedWithdrawals)) + fmt.Printf("Consider checkpointing to claim beacon rewards, or depositing ETH and checkpointing to complete these withdrawals.\n\n") + } + + fmt.Printf("Your podOwner(%s) has %d withdrawals that can be completed right now.\n", podOwner.Hex(), len(affordedWithdrawals)) + fmt.Printf("Total ETH: %sETH\n", core.GweiToEther(core.WeiToGwei(new(big.Int).SetUint64(runningSum))).String()) + + core.PanicIfNoConsent("Would you like to continue?") + + withdrawals := Map(affordedWithdrawals, func(w *IDelegationManager.IDelegationManagerTypesWithdrawal, i int) IDelegationManager.IDelegationManagerTypesWithdrawal { + return *w + }) + + tokens := Map(withdrawals, func(_ IDelegationManager.IDelegationManagerTypesWithdrawal, _ int) []common.Address { + return []common.Address{common.BigToAddress(big.NewInt(0))} + }) + + receiveAsTokens := Map(withdrawals, func(_ IDelegationManager.IDelegationManagerTypesWithdrawal, _ int) bool { + return true + }) + + txn, err := delegationManager.CompleteQueuedWithdrawals0(nil, withdrawals, tokens, receiveAsTokens) + core.PanicOnError("CompleteQueuedWithdrawals failed.", err) + + fmt.Printf("%s\n", txn.Hash()) + return nil } diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index 32698ae6..d793bd66 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -1,6 +1,12 @@ package commands -import "github.com/pkg/errors" +import ( + "context" + + "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/pkg/errors" +) type TQueueWithdrawallArgs struct { EthNode string @@ -10,10 +16,17 @@ type TQueueWithdrawallArgs struct { func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { // TODO: IDelegationManager.queueWithdrawals + ctx := context.Background() + eth, _, chainId, err := core.GetClients(ctx, args.EthNode, args.BeaconNode, false /* isVerbose */) + dm, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) + + // TODO: wait for G's conversion function from deposit[ed] shares to depositShares + // bound the withdrawals by REG - (sum(allWithdrawalsQueued)) + /* struct QueuedWithdrawalParams { // Array of strategies that the QueuedWithdrawal contains - IStrategy[] strategies; + IStrategy[] strategies; // native eth strategy // Array containing the amount of depositShares for withdrawal in each Strategy in the `strategies` array // Note that the actual shares received on completing withdrawal may be less than the depositShares if slashing occurred uint256[] depositShares; diff --git a/cli/commands/showWithdrawals.go b/cli/commands/showWithdrawals.go index e3ab5ce1..55dc181f 100644 --- a/cli/commands/showWithdrawals.go +++ b/cli/commands/showWithdrawals.go @@ -1,6 +1,17 @@ package commands -import "github.com/pkg/errors" +import ( + "context" + "math/big" + "time" + + . "github.com/samber/lo" + + "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" + "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/ethereum/go-ethereum/common" +) type TShowWithdrawalArgs struct { EthNode string @@ -9,6 +20,60 @@ type TShowWithdrawalArgs struct { } func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { - // IDelegationManager.getQueuedWithdrawals - return errors.New("unimplemented.") + ctx := context.Background() + eth, _, chainId, err := core.GetClients(ctx, args.EthNode, args.BeaconNode, false /* isVerbose */) + core.PanicOnError("failed to reach eth and beacon node", err) + + curBlock, err := eth.BlockByNumber(ctx, nil) /* head */ + core.PanicOnError("failed to load curBlock", err) + + genBlock, err := eth.BlockByNumber(ctx, big.NewInt(0)) /* head */ + core.PanicOnError("failed to load genesis block", err) + + timePerBlockSeconds := float64(curBlock.NumberU64()-genBlock.NumberU64()) / float64(curBlock.Time()-genBlock.Time()) + + dm, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) + core.PanicOnError("failed to reach delegation manager", err) + + pod, err := EigenPod.NewEigenPod(common.HexToAddress(args.EigenPod), eth) + core.PanicOnError("failed to reach eigenpod manager", err) + + podOwner, err := pod.PodOwner(nil) + core.PanicOnError("failed to load podOwner", err) + + allWithdrawals, err := dm.GetQueuedWithdrawals(nil, podOwner) + core.PanicOnError("failed to get queued withdrawals", err) + + type TWithdrawalInfo struct { + Staker string + AvailableAfter string + AvailableAfterBlock *big.Int + Ready bool + TotalAmountETH *big.Float + } + + minDelay, err := dm.MinWithdrawalDelayBlocks(nil) + core.PanicOnError("failed to get minWithdrawalDelay", err) + + withdrawalInfo := []TWithdrawalInfo{} + + for i, shares := range allWithdrawals.Shares { + withdrawalTotalValueWei := Reduce(shares, func(accum *big.Int, item *big.Int, i int) *big.Int { + return new(big.Int).Add(item, accum) + }, big.NewInt(0)) + + targetBlock := new(big.Int).SetUint64(uint64(allWithdrawals.Withdrawals[i].StartBlock + minDelay)) + + blockDeltaSeconds := (targetBlock.Uint64() - curBlock.NumberU64()) * uint64(timePerBlockSeconds) + availableAfter := time.Now().Add(time.Second * time.Duration(blockDeltaSeconds)) + + withdrawalInfo = append(withdrawalInfo, TWithdrawalInfo{ + TotalAmountETH: core.GweiToEther(core.WeiToGwei(withdrawalTotalValueWei)), + Staker: allWithdrawals.Withdrawals[i].Staker.Hex(), + AvailableAfterBlock: targetBlock, + AvailableAfter: availableAfter.String(), + Ready: targetBlock.Uint64() <= curBlock.NumberU64(), + }) + } + return nil } diff --git a/cli/flags.go b/cli/flags.go index 31e02ef0..f01eca88 100644 --- a/cli/flags.go +++ b/cli/flags.go @@ -12,6 +12,15 @@ var PodAddressFlag = &cli.StringFlag{ Destination: &eigenpodAddress, } +var PodOwnerFlag = &cli.StringFlag{ + Name: "podOwner", + Aliases: []string{"p", "podOwner"}, + Value: "", + Usage: "[required] The onchain `address` of your eigenpod's owner (0x123123123123)", + Required: true, + Destination: &eigenpodOwner, +} + // Required for commands that need a beacon chain RPC var BeaconNodeFlag = &cli.StringFlag{ Name: "beaconNode", diff --git a/cli/main.go b/cli/main.go index 3194febc..3be831bc 100644 --- a/cli/main.go +++ b/cli/main.go @@ -10,7 +10,7 @@ import ( ) // Destinations for values set by various flags -var eigenpodAddress, beacon, node, sender string +var eigenpodAddress, beacon, node, sender, eigenpodOwner string var useJSON = false var specificValidator uint64 = math.MaxUint64 var estimateGas = false diff --git a/go.mod b/go.mod index e737d3e5..1e49bd07 100644 --- a/go.mod +++ b/go.mod @@ -57,6 +57,7 @@ require ( github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 // indirect github.com/r3labs/sse/v2 v2.10.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/samber/lo v1.47.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/supranational/blst v0.3.13 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect @@ -71,6 +72,7 @@ require ( golang.org/x/net v0.29.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect diff --git a/go.sum b/go.sum index 941725d2..e27c1884 100644 --- a/go.sum +++ b/go.sum @@ -189,6 +189,8 @@ github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= +github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= From b23d4a3dbf75901cb39627ac817c365952dc6824 Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Tue, 17 Dec 2024 18:17:42 -0500 Subject: [PATCH 04/25] save --- cli/commands/queueWithdrawal.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index d793bd66..8e365b31 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -15,10 +15,12 @@ type TQueueWithdrawallArgs struct { } func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { - // TODO: IDelegationManager.queueWithdrawals ctx := context.Background() eth, _, chainId, err := core.GetClients(ctx, args.EthNode, args.BeaconNode, false /* isVerbose */) - dm, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) + core.PanicOnError("failed to dial nodes", err) + + _dm, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) + core.PanicOnError("failed to reach delegation manager", err) // TODO: wait for G's conversion function from deposit[ed] shares to depositShares // bound the withdrawals by REG - (sum(allWithdrawalsQueued)) From 6a3eb67814a3aaed40e8df96b329de04d2d0481c Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Tue, 17 Dec 2024 18:27:56 -0500 Subject: [PATCH 05/25] rm unnecessary args --- cli/commands/completeAllWithdrawals.go | 29 ++++++++++++++++---------- cli/commands/queueWithdrawal.go | 17 +++++++++------ cli/commands/showWithdrawals.go | 4 ++-- cli/main.go | 22 +++++++++---------- 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index 98481ba2..ef0140f7 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -5,18 +5,19 @@ import ( "fmt" "math/big" - . "github.com/samber/lo" + lo "github.com/samber/lo" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" ) type TCompleteWithdrawalArgs struct { - EthNode string - BeaconNode string - EigenPod string + EthNode string + EigenPod string + Sender string } func DelegationManager(chainId *big.Int) common.Address { @@ -35,7 +36,13 @@ func DelegationManager(chainId *big.Int) common.Address { func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { ctx := context.Background() - eth, _, chainId, err := core.GetClients(ctx, args.EthNode, args.BeaconNode, false /* isVerbose */) + + eth, err := ethclient.DialContext(ctx, args.EthNode) + core.PanicOnError("failed to reach eth node", err) + + chainId, err := eth.ChainID(nil) + core.PanicOnError("failed to load chainId", err) + curBlockNumber, err := eth.BlockNumber(nil) pod, err := EigenPod.NewEigenPod(common.HexToAddress(args.EigenPod), eth) @@ -58,7 +65,7 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { beaconETHStrategy := common.HexToAddress("0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0") - eligibleWithdrawals := Map(queuedWithdrawals.Withdrawals, func(withdrawal IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { + eligibleWithdrawals := lo.Map(queuedWithdrawals.Withdrawals, func(withdrawal IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { isBeaconWithdrawal := len(withdrawal.Strategies) == 1 && withdrawal.Strategies[0].Cmp(beaconETHStrategy) == 0 isExecutable := curBlockNumber <= uint64(withdrawal.StartBlock+minDelay) if isBeaconWithdrawal && isExecutable { @@ -68,7 +75,7 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { }) var runningSum uint64 = 0 - affordedWithdrawals := Map(eligibleWithdrawals, func(withdrawal *IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { + affordedWithdrawals := lo.Map(eligibleWithdrawals, func(withdrawal *IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { if withdrawal == nil { return nil } @@ -81,7 +88,7 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { }) // filter out any nils. - affordedWithdrawals = Filter(affordedWithdrawals, func(withdrawal *IDelegationManager.IDelegationManagerTypesWithdrawal, index int) bool { + affordedWithdrawals = lo.Filter(affordedWithdrawals, func(withdrawal *IDelegationManager.IDelegationManagerTypesWithdrawal, index int) bool { return withdrawal != nil }) @@ -95,15 +102,15 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { core.PanicIfNoConsent("Would you like to continue?") - withdrawals := Map(affordedWithdrawals, func(w *IDelegationManager.IDelegationManagerTypesWithdrawal, i int) IDelegationManager.IDelegationManagerTypesWithdrawal { + withdrawals := lo.Map(affordedWithdrawals, func(w *IDelegationManager.IDelegationManagerTypesWithdrawal, i int) IDelegationManager.IDelegationManagerTypesWithdrawal { return *w }) - tokens := Map(withdrawals, func(_ IDelegationManager.IDelegationManagerTypesWithdrawal, _ int) []common.Address { + tokens := lo.Map(withdrawals, func(_ IDelegationManager.IDelegationManagerTypesWithdrawal, _ int) []common.Address { return []common.Address{common.BigToAddress(big.NewInt(0))} }) - receiveAsTokens := Map(withdrawals, func(_ IDelegationManager.IDelegationManagerTypesWithdrawal, _ int) bool { + receiveAsTokens := lo.Map(withdrawals, func(_ IDelegationManager.IDelegationManagerTypesWithdrawal, _ int) bool { return true }) diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index 8e365b31..04e9f195 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -5,21 +5,26 @@ import ( "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/ethereum/go-ethereum/ethclient" "github.com/pkg/errors" ) type TQueueWithdrawallArgs struct { - EthNode string - BeaconNode string - EigenPod string + EthNode string + EigenPod string + Sender string } func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { ctx := context.Background() - eth, _, chainId, err := core.GetClients(ctx, args.EthNode, args.BeaconNode, false /* isVerbose */) - core.PanicOnError("failed to dial nodes", err) - _dm, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) + eth, err := ethclient.DialContext(ctx, args.EthNode) + core.PanicOnError("failed to reach eth node", err) + + chainId, err := eth.ChainID(nil) + core.PanicOnError("failed to load chainId", err) + + _, err = IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) core.PanicOnError("failed to reach delegation manager", err) // TODO: wait for G's conversion function from deposit[ed] shares to depositShares diff --git a/cli/commands/showWithdrawals.go b/cli/commands/showWithdrawals.go index 55dc181f..b8c03d73 100644 --- a/cli/commands/showWithdrawals.go +++ b/cli/commands/showWithdrawals.go @@ -5,7 +5,7 @@ import ( "math/big" "time" - . "github.com/samber/lo" + lo "github.com/samber/lo" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" @@ -58,7 +58,7 @@ func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { withdrawalInfo := []TWithdrawalInfo{} for i, shares := range allWithdrawals.Shares { - withdrawalTotalValueWei := Reduce(shares, func(accum *big.Int, item *big.Int, i int) *big.Int { + withdrawalTotalValueWei := lo.Reduce(shares, func(accum *big.Int, item *big.Int, i int) *big.Int { return new(big.Int).Add(item, accum) }, big.NewInt(0)) diff --git a/cli/main.go b/cli/main.go index 3be831bc..47c9060c 100644 --- a/cli/main.go +++ b/cli/main.go @@ -202,14 +202,14 @@ func main() { Usage: "Completes all withdrawals", Flags: []cli.Flag{ ExecNodeFlag, - BeaconNodeFlag, PodAddressFlag, + SenderPkFlag, }, Action: func(_ *cli.Context) error { return commands.CompleteAllWithdrawalsCommand(commands.TCompleteWithdrawalArgs{ - EthNode: node, - BeaconNode: beacon, - EigenPod: eigenpodAddress, + EthNode: node, + EigenPod: eigenpodAddress, + Sender: sender, }) }, }, @@ -219,14 +219,14 @@ func main() { Usage: "Queues a withdrawal", Flags: []cli.Flag{ ExecNodeFlag, - BeaconNodeFlag, PodAddressFlag, + SenderPkFlag, }, Action: func(_ *cli.Context) error { return commands.QueueWithdrawalCommand(commands.TQueueWithdrawallArgs{ - EthNode: node, - BeaconNode: beacon, - EigenPod: eigenpodAddress, + EthNode: node, + EigenPod: eigenpodAddress, + Sender: sender, }) }, }, @@ -236,14 +236,12 @@ func main() { Usage: "Shows all pending withdrawals", Flags: []cli.Flag{ ExecNodeFlag, - BeaconNodeFlag, PodAddressFlag, }, Action: func(_ *cli.Context) error { return commands.ShowWithdrawalsCommand(commands.TShowWithdrawalArgs{ - EthNode: node, - BeaconNode: beacon, - EigenPod: eigenpodAddress, + EthNode: node, + EigenPod: eigenpodAddress, }) }, }, From 9a1ff013aa30947064ca49570bd7da39c4d236fe Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Tue, 17 Dec 2024 18:31:45 -0500 Subject: [PATCH 06/25] Fix lint --- .golangci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 48b24d48..9463c636 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -12,7 +12,7 @@ linters-settings: - performance - style govet: - check-shadowing: true + shadow: true enable: - fieldalignment nolintlint: @@ -26,12 +26,11 @@ linters: - dogsled - dupl - errcheck - - exportloopref + - copyloopvar - exhaustive - goconst - gocritic - gofmt - - gomnd - gocyclo - gosec - gosimple From fccb46e44fc00ddb410ccff07680e387c543fda5 Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 14:26:04 -0500 Subject: [PATCH 07/25] finish initial impl, just missing PrepareAccount calls --- cli/commands/completeAllWithdrawals.go | 11 ++-- cli/commands/queueWithdrawal.go | 69 ++++++++++++++++++++------ cli/commands/showWithdrawals.go | 10 ++++ cli/core/status.go | 9 ++-- go.mod | 4 +- go.sum | 4 +- 6 files changed, 78 insertions(+), 29 deletions(-) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index ef0140f7..1712822c 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -40,10 +40,11 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { eth, err := ethclient.DialContext(ctx, args.EthNode) core.PanicOnError("failed to reach eth node", err) - chainId, err := eth.ChainID(nil) + chainId, err := eth.ChainID(ctx) core.PanicOnError("failed to load chainId", err) - curBlockNumber, err := eth.BlockNumber(nil) + curBlockNumber, err := eth.BlockNumber(ctx) + core.PanicOnError("failed to load current block number", err) pod, err := EigenPod.NewEigenPod(common.HexToAddress(args.EigenPod), eth) core.PanicOnError("failed to reach eigenpod", err) @@ -63,10 +64,8 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { queuedWithdrawals, err := delegationManager.GetQueuedWithdrawals(nil, podOwner) core.PanicOnError("failed to read queuedWithdrawals", err) - beaconETHStrategy := common.HexToAddress("0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0") - eligibleWithdrawals := lo.Map(queuedWithdrawals.Withdrawals, func(withdrawal IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { - isBeaconWithdrawal := len(withdrawal.Strategies) == 1 && withdrawal.Strategies[0].Cmp(beaconETHStrategy) == 0 + isBeaconWithdrawal := len(withdrawal.Strategies) == 1 && withdrawal.Strategies[0].Cmp(core.BeaconStrategy()) == 0 isExecutable := curBlockNumber <= uint64(withdrawal.StartBlock+minDelay) if isBeaconWithdrawal && isExecutable { return &withdrawal @@ -114,7 +113,7 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { return true }) - txn, err := delegationManager.CompleteQueuedWithdrawals0(nil, withdrawals, tokens, receiveAsTokens) + txn, err := delegationManager.CompleteQueuedWithdrawals(nil, withdrawals, tokens, receiveAsTokens) core.PanicOnError("CompleteQueuedWithdrawals failed.", err) fmt.Printf("%s\n", txn.Hash()) diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index 04e9f195..9a39a9d4 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -2,11 +2,14 @@ package commands import ( "context" + "fmt" + "math/big" + "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" - "github.com/pkg/errors" ) type TQueueWithdrawallArgs struct { @@ -24,22 +27,58 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { chainId, err := eth.ChainID(nil) core.PanicOnError("failed to load chainId", err) - _, err = IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) + dm, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) core.PanicOnError("failed to reach delegation manager", err) - // TODO: wait for G's conversion function from deposit[ed] shares to depositShares // bound the withdrawals by REG - (sum(allWithdrawalsQueued)) - /* - struct QueuedWithdrawalParams { - // Array of strategies that the QueuedWithdrawal contains - IStrategy[] strategies; // native eth strategy - // Array containing the amount of depositShares for withdrawal in each Strategy in the `strategies` array - // Note that the actual shares received on completing withdrawal may be less than the depositShares if slashing occurred - uint256[] depositShares; - // The address of the withdrawer - address withdrawer; - } - */ - return errors.New("unimplemented.") + pod, err := EigenPod.NewEigenPod(common.HexToAddress(args.EigenPod), eth) + core.PanicOnError("failed to reach eigenpod", err) + + _reg, err := pod.WithdrawableRestakedExecutionLayerGwei(nil) + core.PanicOnError("failed to load REG", err) + reg := new(big.Int).SetUint64(_reg) + + podOwner, err := pod.PodOwner(nil) + core.PanicOnError("failed to read podOwner", err) + + res, err := dm.GetWithdrawableShares(nil, podOwner, []common.Address{core.BeaconStrategy()}) + core.PanicOnError("failed to read beacon strategy withdrawable shares", err) + + _depositShares, err := dm.ConvertToDepositShares(nil, podOwner, []common.Address{core.BeaconStrategy()}, []*big.Int{res.WithdrawableShares[0]}) + core.PanicOnError("failed to compute deposit shares", err) + depositShares := _depositShares[0] + + minWithdrawalDelay, err := dm.MinWithdrawalDelayBlocks(nil) + curBlock, err := eth.BlockNumber(ctx) + + core.PanicOnError("failed to load minimum withdrawal delay", err) + + depositSharesGwei := core.IGweiToWei(depositShares) + + var amountToWithdrawDepositShares *big.Int = new(big.Int) + *amountToWithdrawDepositShares = *depositSharesGwei + + fmt.Printf("In the Native ETH strategy, you have %sETH to be withdrawn.\n", core.GweiToEther(new(big.Float).SetInt(depositSharesGwei))) + fmt.Printf("NOTE: If you were or become slashed on EigenLayer during the withdrawal period, the total amount received will be less any slashed amount.\n") + + if depositSharesGwei.Cmp(reg) > 0 { + fmt.Printf("Queueing a partial withdrawal. Your pod only had %sETH available to satisfy withdrawals.") + fmt.Printf("Checkpointing may update this balance, if you have any uncheckpointed native eth or beacon rewards.") + *amountToWithdrawDepositShares = *reg + } + + core.PanicIfNoConsent(fmt.Sprintf("Would you like to queue a withdrawal %sETH from the Native ETH strategy? This will be withdrawable after approximately block #%d (current block: %d)\n", amountToWithdrawDepositShares, curBlock+uint64(minWithdrawalDelay), curBlock)) + + txn, err := dm.QueueWithdrawals(nil, []IDelegationManager.IDelegationManagerTypesQueuedWithdrawalParams{ + IDelegationManager.IDelegationManagerTypesQueuedWithdrawalParams{ + Strategies: []common.Address{core.BeaconStrategy()}, + DepositShares: []*big.Int{amountToWithdrawDepositShares}, + Withdrawer: podOwner, + }, + }) + core.PanicOnError("failed to queue withdrawal", err) + + fmt.Printf("Txn: %s\n", txn.Hash().Hex()) + return nil } diff --git a/cli/commands/showWithdrawals.go b/cli/commands/showWithdrawals.go index b8c03d73..3a01af3e 100644 --- a/cli/commands/showWithdrawals.go +++ b/cli/commands/showWithdrawals.go @@ -2,6 +2,8 @@ package commands import ( "context" + "encoding/json" + "fmt" "math/big" "time" @@ -17,6 +19,7 @@ type TShowWithdrawalArgs struct { EthNode string BeaconNode string EigenPod string + Strategies common.Address } func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { @@ -46,6 +49,7 @@ func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { type TWithdrawalInfo struct { Staker string + Strategies []common.Address AvailableAfter string AvailableAfterBlock *big.Int Ready bool @@ -69,11 +73,17 @@ func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { withdrawalInfo = append(withdrawalInfo, TWithdrawalInfo{ TotalAmountETH: core.GweiToEther(core.WeiToGwei(withdrawalTotalValueWei)), + Strategies: allWithdrawals.Withdrawals[i].Strategies, Staker: allWithdrawals.Withdrawals[i].Staker.Hex(), AvailableAfterBlock: targetBlock, AvailableAfter: availableAfter.String(), Ready: targetBlock.Uint64() <= curBlock.NumberU64(), }) } + + jsonBytes, err := json.MarshalIndent(withdrawalInfo, "", " ") + core.PanicOnError("failed to serialize", err) + fmt.Println(string(jsonBytes)) + return nil } diff --git a/cli/core/status.go b/cli/core/status.go index 5a848e9c..b6fe1b86 100644 --- a/cli/core/status.go +++ b/cli/core/status.go @@ -10,7 +10,6 @@ import ( "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPodManager" "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" - "github.com/ethereum/go-ethereum/common" gethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" ) @@ -31,7 +30,9 @@ type Validator struct { CurrentBalance uint64 } -const NATIVE_ETH_STRATEGY = "0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0" +func BeaconStrategy() gethCommon.Address { + return gethCommon.HexToAddress("0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0") +} type EigenpodStatus struct { Validators map[string]Validator @@ -155,8 +156,8 @@ func GetStatus(ctx context.Context, eigenpodAddress string, eth *ethclient.Clien delegationManager, err := DelegationManager.NewDelegationManager(delegationManagerAddress, eth) PanicOnError("failed to reach delegationManager", err) - shares, err := delegationManager.GetWithdrawableShares(nil, eigenPodOwner, []common.Address{ - common.HexToAddress(NATIVE_ETH_STRATEGY), + shares, err := delegationManager.GetWithdrawableShares(nil, eigenPodOwner, []gethCommon.Address{ + BeaconStrategy(), }) PanicOnError("failed to load owner shares", err) diff --git a/go.mod b/go.mod index 1e49bd07..560241c2 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.0 toolchain go1.22.4 require ( - github.com/Layr-Labs/eigenlayer-contracts v0.4.3-mainnet-rewards-foundation-incentives.0.20241216232148-75428be65f85 + github.com/Layr-Labs/eigenlayer-contracts v0.4.3-mainnet-rewards-foundation-incentives.0.20241218180135-1856b33e74ac github.com/attestantio/go-eth2-client v0.19.9 github.com/ethereum/go-ethereum v1.14.9 github.com/fatih/color v1.16.0 @@ -15,6 +15,7 @@ require ( github.com/minio/sha256-simd v1.0.1 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.29.1 + github.com/samber/lo v1.47.0 github.com/stretchr/testify v1.9.0 github.com/urfave/cli/v2 v2.27.1 ) @@ -57,7 +58,6 @@ require ( github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 // indirect github.com/r3labs/sse/v2 v2.10.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/samber/lo v1.47.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/supranational/blst v0.3.13 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect diff --git a/go.sum b/go.sum index e27c1884..5c73e8d2 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/Layr-Labs/eigenlayer-contracts v0.4.3-mainnet-rewards-foundation-incentives.0.20241216232148-75428be65f85 h1:nyMTaafrT29KlAKFisfhVVCRU+MZucnnIgO3M8M6qe0= -github.com/Layr-Labs/eigenlayer-contracts v0.4.3-mainnet-rewards-foundation-incentives.0.20241216232148-75428be65f85/go.mod h1:Ie8YE3EQkTHqG6/tnUS0He7/UPMkXPo/3OFXwSy0iRo= +github.com/Layr-Labs/eigenlayer-contracts v0.4.3-mainnet-rewards-foundation-incentives.0.20241218180135-1856b33e74ac h1:YKNXU2HFHxdR7XyrUxeXyVWf2u5tMCwKA3/2YKT54Oo= +github.com/Layr-Labs/eigenlayer-contracts v0.4.3-mainnet-rewards-foundation-incentives.0.20241218180135-1856b33e74ac/go.mod h1:Ie8YE3EQkTHqG6/tnUS0He7/UPMkXPo/3OFXwSy0iRo= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= From 7ae70fb41583a8a2711e57b3f82d534611e9af70 Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 14:48:42 -0500 Subject: [PATCH 08/25] build and lint --- cli/commands/completeAllWithdrawals.go | 35 +++++++++++++++---- cli/commands/queueWithdrawal.go | 47 +++++++++++++++++++------- cli/commands/showWithdrawals.go | 7 +--- cli/main.go | 16 +++++---- 4 files changed, 73 insertions(+), 32 deletions(-) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index 1712822c..b65b6360 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -15,9 +15,10 @@ import ( ) type TCompleteWithdrawalArgs struct { - EthNode string - EigenPod string - Sender string + EthNode string + EigenPod string + Sender string + EstimateGas bool } func DelegationManager(chainId *big.Int) common.Address { @@ -37,12 +38,17 @@ func DelegationManager(chainId *big.Int) common.Address { func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { ctx := context.Background() + isSimulation := args.EstimateGas + eth, err := ethclient.DialContext(ctx, args.EthNode) core.PanicOnError("failed to reach eth node", err) chainId, err := eth.ChainID(ctx) core.PanicOnError("failed to load chainId", err) + acc, err := core.PrepareAccount(&args.Sender, chainId, isSimulation) + core.PanicOnError("failed to parse private key", err) + curBlockNumber, err := eth.BlockNumber(ctx) core.PanicOnError("failed to load current block number", err) @@ -86,7 +92,6 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { return nil }) - // filter out any nils. affordedWithdrawals = lo.Filter(affordedWithdrawals, func(withdrawal *IDelegationManager.IDelegationManagerTypesWithdrawal, index int) bool { return withdrawal != nil }) @@ -99,7 +104,11 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { fmt.Printf("Your podOwner(%s) has %d withdrawals that can be completed right now.\n", podOwner.Hex(), len(affordedWithdrawals)) fmt.Printf("Total ETH: %sETH\n", core.GweiToEther(core.WeiToGwei(new(big.Int).SetUint64(runningSum))).String()) - core.PanicIfNoConsent("Would you like to continue?") + if !isSimulation { + core.PanicIfNoConsent("Would you like to continue?") + } else { + fmt.Printf("THIS IS A SIMULATION. No transaction will be recorded onchain.\n") + } withdrawals := lo.Map(affordedWithdrawals, func(w *IDelegationManager.IDelegationManagerTypesWithdrawal, i int) IDelegationManager.IDelegationManagerTypesWithdrawal { return *w @@ -113,9 +122,21 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { return true }) - txn, err := delegationManager.CompleteQueuedWithdrawals(nil, withdrawals, tokens, receiveAsTokens) + txn, err := delegationManager.CompleteQueuedWithdrawals(acc.TransactionOptions, withdrawals, tokens, receiveAsTokens) core.PanicOnError("CompleteQueuedWithdrawals failed.", err) - fmt.Printf("%s\n", txn.Hash()) + if !isSimulation { + fmt.Printf("%s\n", txn.Hash().Hex()) + } else { + printAsJSON(Transaction{ + Type: "complete-withdrawals", + To: txn.To().Hex(), + CallData: common.Bytes2Hex(txn.Data()), + GasEstimateGwei: func() *uint64 { + gas := txn.Gas() + return &gas + }(), + }) + } return nil } diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index 9a39a9d4..b9985ced 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -13,25 +13,29 @@ import ( ) type TQueueWithdrawallArgs struct { - EthNode string - EigenPod string - Sender string + EthNode string + EigenPod string + Sender string + EstimateGas bool } func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { ctx := context.Background() + isSimulation := args.EstimateGas + eth, err := ethclient.DialContext(ctx, args.EthNode) core.PanicOnError("failed to reach eth node", err) - chainId, err := eth.ChainID(nil) + chainId, err := eth.ChainID(ctx) core.PanicOnError("failed to load chainId", err) + acc, err := core.PrepareAccount(&args.Sender, chainId, args.EstimateGas) + core.PanicOnError("failed to parse private key", err) + dm, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) core.PanicOnError("failed to reach delegation manager", err) - // bound the withdrawals by REG - (sum(allWithdrawalsQueued)) - pod, err := EigenPod.NewEigenPod(common.HexToAddress(args.EigenPod), eth) core.PanicOnError("failed to reach eigenpod", err) @@ -50,7 +54,10 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { depositShares := _depositShares[0] minWithdrawalDelay, err := dm.MinWithdrawalDelayBlocks(nil) + core.PanicOnError("failed to load minWithdrawalDelay", err) + curBlock, err := eth.BlockNumber(ctx) + core.PanicOnError("failed to load current block number", err) core.PanicOnError("failed to load minimum withdrawal delay", err) @@ -63,22 +70,36 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { fmt.Printf("NOTE: If you were or become slashed on EigenLayer during the withdrawal period, the total amount received will be less any slashed amount.\n") if depositSharesGwei.Cmp(reg) > 0 { - fmt.Printf("Queueing a partial withdrawal. Your pod only had %sETH available to satisfy withdrawals.") + fmt.Printf("Queueing a partial withdrawal. Your pod only had %sETH available to satisfy withdrawals.", core.GweiToEther(new(big.Float).SetInt(reg)).String()) fmt.Printf("Checkpointing may update this balance, if you have any uncheckpointed native eth or beacon rewards.") *amountToWithdrawDepositShares = *reg } - core.PanicIfNoConsent(fmt.Sprintf("Would you like to queue a withdrawal %sETH from the Native ETH strategy? This will be withdrawable after approximately block #%d (current block: %d)\n", amountToWithdrawDepositShares, curBlock+uint64(minWithdrawalDelay), curBlock)) - - txn, err := dm.QueueWithdrawals(nil, []IDelegationManager.IDelegationManagerTypesQueuedWithdrawalParams{ - IDelegationManager.IDelegationManagerTypesQueuedWithdrawalParams{ + if !isSimulation { + core.PanicIfNoConsent(fmt.Sprintf("Would you like to queue a withdrawal %sETH from the Native ETH strategy? This will be withdrawable after approximately block #%d (current block: %d)\n", amountToWithdrawDepositShares, curBlock+uint64(minWithdrawalDelay), curBlock)) + } else { + fmt.Printf("THIS IS A SIMULATION. No transaction will be recorded onchain.\n") + } + txn, err := dm.QueueWithdrawals(acc.TransactionOptions, []IDelegationManager.IDelegationManagerTypesQueuedWithdrawalParams{ + { Strategies: []common.Address{core.BeaconStrategy()}, DepositShares: []*big.Int{amountToWithdrawDepositShares}, Withdrawer: podOwner, }, }) core.PanicOnError("failed to queue withdrawal", err) - - fmt.Printf("Txn: %s\n", txn.Hash().Hex()) + if !isSimulation { + fmt.Printf("%s\n", txn.Hash().Hex()) + } else { + printAsJSON(Transaction{ + Type: "queue-withdrawal", + To: txn.To().Hex(), + CallData: common.Bytes2Hex(txn.Data()), + GasEstimateGwei: func() *uint64 { + gas := txn.Gas() + return &gas + }(), + }) + } return nil } diff --git a/cli/commands/showWithdrawals.go b/cli/commands/showWithdrawals.go index 3a01af3e..41b4e38e 100644 --- a/cli/commands/showWithdrawals.go +++ b/cli/commands/showWithdrawals.go @@ -2,8 +2,6 @@ package commands import ( "context" - "encoding/json" - "fmt" "math/big" "time" @@ -81,9 +79,6 @@ func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { }) } - jsonBytes, err := json.MarshalIndent(withdrawalInfo, "", " ") - core.PanicOnError("failed to serialize", err) - fmt.Println(string(jsonBytes)) - + printAsJSON(withdrawalInfo) return nil } diff --git a/cli/main.go b/cli/main.go index 47c9060c..7691cfc0 100644 --- a/cli/main.go +++ b/cli/main.go @@ -204,12 +204,14 @@ func main() { ExecNodeFlag, PodAddressFlag, SenderPkFlag, + EstimateGasFlag, }, Action: func(_ *cli.Context) error { return commands.CompleteAllWithdrawalsCommand(commands.TCompleteWithdrawalArgs{ - EthNode: node, - EigenPod: eigenpodAddress, - Sender: sender, + EthNode: node, + EigenPod: eigenpodAddress, + Sender: sender, + EstimateGas: estimateGas, }) }, }, @@ -221,12 +223,14 @@ func main() { ExecNodeFlag, PodAddressFlag, SenderPkFlag, + EstimateGasFlag, }, Action: func(_ *cli.Context) error { return commands.QueueWithdrawalCommand(commands.TQueueWithdrawallArgs{ - EthNode: node, - EigenPod: eigenpodAddress, - Sender: sender, + EthNode: node, + EigenPod: eigenpodAddress, + Sender: sender, + EstimateGas: estimateGas, }) }, }, From 614f53cca9e0a15e3a9511f106261bcbfe585a9f Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 15:10:05 -0500 Subject: [PATCH 09/25] add more docs --- cli/main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/main.go b/cli/main.go index 7691cfc0..37b2100b 100644 --- a/cli/main.go +++ b/cli/main.go @@ -199,7 +199,7 @@ func main() { { Name: "complete-all-withdrawals", Args: true, - Usage: "Completes all withdrawals", + Usage: "Completes all withdrawals queued on the podOwner, for which Native ETH is the sole strategy in the withdrawal. Attempts to execute a group of withdrawals whose sum does not exceed Pod.withdrawableRestakedExecutionLayerGwei() in value.", Flags: []cli.Flag{ ExecNodeFlag, PodAddressFlag, @@ -218,7 +218,7 @@ func main() { { Name: "queue-withdrawal", Args: true, - Usage: "Queues a withdrawal", + Usage: "Queues a withdrawal for shares associated with the native ETH strategy. Queues a withdrawal whose size does not exceed Pod.withdrawableRestakedExecutionLayerGwei() in value.", Flags: []cli.Flag{ ExecNodeFlag, PodAddressFlag, @@ -237,7 +237,7 @@ func main() { { Name: "show-withdrawals", Args: true, - Usage: "Shows all pending withdrawals", + Usage: "Shows all pending withdrawals for the podOwner.", Flags: []cli.Flag{ ExecNodeFlag, PodAddressFlag, From f5b1b2ada9633688033e6750ed65cdc0abc2713a Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 15:12:51 -0500 Subject: [PATCH 10/25] fix isExecutable --- cli/commands/completeAllWithdrawals.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index b65b6360..dd895dd8 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -72,7 +72,7 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { eligibleWithdrawals := lo.Map(queuedWithdrawals.Withdrawals, func(withdrawal IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { isBeaconWithdrawal := len(withdrawal.Strategies) == 1 && withdrawal.Strategies[0].Cmp(core.BeaconStrategy()) == 0 - isExecutable := curBlockNumber <= uint64(withdrawal.StartBlock+minDelay) + isExecutable := curBlockNumber >= uint64(withdrawal.StartBlock+minDelay) if isBeaconWithdrawal && isExecutable { return &withdrawal } From d4a32f9b91cd5098c0d8b39dcdb51611d87f5184 Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 15:15:02 -0500 Subject: [PATCH 11/25] early return with no afforded or none at all --- cli/commands/completeAllWithdrawals.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index dd895dd8..38896860 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -5,6 +5,7 @@ import ( "fmt" "math/big" + "github.com/pkg/errors" lo "github.com/samber/lo" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" @@ -79,6 +80,11 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { return nil }) + if len(eligibleWithdrawals) == 0 { + fmt.Printf("Your pod has no eligible withdrawals.\n") + return nil + } + var runningSum uint64 = 0 affordedWithdrawals := lo.Map(eligibleWithdrawals, func(withdrawal *IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { if withdrawal == nil { @@ -96,6 +102,12 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { return withdrawal != nil }) + if len(affordedWithdrawals) == 0 && len(eligibleWithdrawals) > 0 { + fmt.Printf("WARN: Your pod has %d withdrawals available, but your pod does not have enough funding to proceed.\n", len(eligibleWithdrawals)) + fmt.Printf("Consider checkpointing to claim beacon rewards, or depositing ETH and checkpointing to complete these withdrawals.\n\n") + return errors.New("Insufficient funds") + } + if len(affordedWithdrawals) != len(eligibleWithdrawals) { fmt.Printf("WARN: Your pod has %d withdrawals available, but you only have enough balance to satisfy %d of them.\n", len(eligibleWithdrawals), len(affordedWithdrawals)) fmt.Printf("Consider checkpointing to claim beacon rewards, or depositing ETH and checkpointing to complete these withdrawals.\n\n") From 6e7c30de86eea991960123656f489732c45cc5e1 Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 15:43:08 -0500 Subject: [PATCH 12/25] add --amountWei field --- cli/commands/queueWithdrawal.go | 41 +++++++++++++++++++++++++-------- cli/flags.go | 8 +++++++ cli/main.go | 3 +++ 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index b9985ced..247342c6 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -2,6 +2,7 @@ package commands import ( "context" + "errors" "fmt" "math/big" @@ -17,6 +18,7 @@ type TQueueWithdrawallArgs struct { EigenPod string Sender string EstimateGas bool + AmountWei uint64 } func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { @@ -41,7 +43,12 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { _reg, err := pod.WithdrawableRestakedExecutionLayerGwei(nil) core.PanicOnError("failed to load REG", err) - reg := new(big.Int).SetUint64(_reg) + + // [withdrawable]RestakedExecutionlayerWei + rew := core.GweiToWei(new(big.Float).SetUint64(_reg)) + if args.AmountWei > 0 && new(big.Float).SetUint64(args.AmountWei).Cmp(rew) > 0 { + return errors.New("invalid --amountWei. must be in the range (0, pod.withdrawableRestakedExecutionLayerGwei() as wei]") + } podOwner, err := pod.PodOwner(nil) core.PanicOnError("failed to read podOwner", err) @@ -49,7 +56,25 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { res, err := dm.GetWithdrawableShares(nil, podOwner, []common.Address{core.BeaconStrategy()}) core.PanicOnError("failed to read beacon strategy withdrawable shares", err) - _depositShares, err := dm.ConvertToDepositShares(nil, podOwner, []common.Address{core.BeaconStrategy()}, []*big.Int{res.WithdrawableShares[0]}) + reg := new(big.Int).SetUint64(_reg) + + requestedWithdrawalSizeWei := func() *big.Int { + if args.AmountWei == 0 { + // if AmountWei isn't specified, we withdraw all the shares in the beacon strategy. + return res.WithdrawableShares[0] + } + + // if it is specified, we withdraw the specific amount. + return new(big.Int).SetUint64(args.AmountWei) + }() + requestedWithdrawalSizeGwei := core.WeiToGwei(requestedWithdrawalSizeWei) + + if requestedWithdrawalSizeGwei.Cmp(new(big.Float).SetInt(res.WithdrawableShares[0])) > 0 { + // requested to withdraw too many shares. + return errors.New("the amount to withdraw is larger than the amount of withdrawable shares in the beacon strategy") + } + + _depositShares, err := dm.ConvertToDepositShares(nil, podOwner, []common.Address{core.BeaconStrategy()}, []*big.Int{requestedWithdrawalSizeWei}) core.PanicOnError("failed to compute deposit shares", err) depositShares := _depositShares[0] @@ -59,12 +84,10 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { curBlock, err := eth.BlockNumber(ctx) core.PanicOnError("failed to load current block number", err) - core.PanicOnError("failed to load minimum withdrawal delay", err) - depositSharesGwei := core.IGweiToWei(depositShares) - var amountToWithdrawDepositShares *big.Int = new(big.Int) - *amountToWithdrawDepositShares = *depositSharesGwei + var amountToWithdrawDepositSharesGwei *big.Int = new(big.Int) + *amountToWithdrawDepositSharesGwei = *depositSharesGwei fmt.Printf("In the Native ETH strategy, you have %sETH to be withdrawn.\n", core.GweiToEther(new(big.Float).SetInt(depositSharesGwei))) fmt.Printf("NOTE: If you were or become slashed on EigenLayer during the withdrawal period, the total amount received will be less any slashed amount.\n") @@ -72,18 +95,18 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { if depositSharesGwei.Cmp(reg) > 0 { fmt.Printf("Queueing a partial withdrawal. Your pod only had %sETH available to satisfy withdrawals.", core.GweiToEther(new(big.Float).SetInt(reg)).String()) fmt.Printf("Checkpointing may update this balance, if you have any uncheckpointed native eth or beacon rewards.") - *amountToWithdrawDepositShares = *reg + *amountToWithdrawDepositSharesGwei = *reg } if !isSimulation { - core.PanicIfNoConsent(fmt.Sprintf("Would you like to queue a withdrawal %sETH from the Native ETH strategy? This will be withdrawable after approximately block #%d (current block: %d)\n", amountToWithdrawDepositShares, curBlock+uint64(minWithdrawalDelay), curBlock)) + core.PanicIfNoConsent(fmt.Sprintf("Would you like to queue a withdrawal %sETH from the Native ETH strategy? This will be withdrawable after approximately block #%d (current block: %d)\n", core.GweiToEther(new(big.Float).SetInt(amountToWithdrawDepositSharesGwei)), curBlock+uint64(minWithdrawalDelay), curBlock)) } else { fmt.Printf("THIS IS A SIMULATION. No transaction will be recorded onchain.\n") } txn, err := dm.QueueWithdrawals(acc.TransactionOptions, []IDelegationManager.IDelegationManagerTypesQueuedWithdrawalParams{ { Strategies: []common.Address{core.BeaconStrategy()}, - DepositShares: []*big.Int{amountToWithdrawDepositShares}, + DepositShares: []*big.Int{core.IGweiToWei(amountToWithdrawDepositSharesGwei)}, Withdrawer: podOwner, }, }) diff --git a/cli/flags.go b/cli/flags.go index f01eca88..27335e2b 100644 --- a/cli/flags.go +++ b/cli/flags.go @@ -60,6 +60,14 @@ var EstimateGasFlag = &cli.BoolFlag{ Destination: &estimateGas, } +var AmountWeiFlag = &cli.Uint64Flag{ + Name: "amountWei", + Aliases: []string{}, + Value: 0, + Usage: "The amount, in Wei.", + Destination: &amountWei, +} + // Optional use for commands that support JSON output var PrintJSONFlag = &cli.BoolFlag{ Name: "json", diff --git a/cli/main.go b/cli/main.go index 37b2100b..0dfb46e8 100644 --- a/cli/main.go +++ b/cli/main.go @@ -15,6 +15,7 @@ var useJSON = false var specificValidator uint64 = math.MaxUint64 var estimateGas = false var slashedValidatorIndex uint64 +var amountWei uint64 const DefaultHealthcheckTolerance = float64(5.0) @@ -224,6 +225,7 @@ func main() { PodAddressFlag, SenderPkFlag, EstimateGasFlag, + AmountWeiFlag, }, Action: func(_ *cli.Context) error { return commands.QueueWithdrawalCommand(commands.TQueueWithdrawallArgs{ @@ -231,6 +233,7 @@ func main() { EigenPod: eigenpodAddress, Sender: sender, EstimateGas: estimateGas, + AmountWei: amountWei, }) }, }, From 795d6c695ae92a67afa74b94fe655b1d0c63201b Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 15:51:55 -0500 Subject: [PATCH 13/25] push --- cli/core/findStalePods.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/core/findStalePods.go b/cli/core/findStalePods.go index 3317473a..400f2494 100644 --- a/cli/core/findStalePods.go +++ b/cli/core/findStalePods.go @@ -42,7 +42,7 @@ func executionWithdrawalAddress(withdrawalCredentials []byte) *string { return &addr } -func validEigenpodsOnly(candidateAddresses []common.Address, mc *multicall.MulticallClient, chainId uint64, eth *ethclient.Client) ([]common.Address, error) { +func validEigenpodsOnly(candidateAddresses []common.Address, mc *multicall.MulticallClient, chainId uint64) ([]common.Address, error) { EigenPodAbi, err := abi.JSON(strings.NewReader(EigenPod.EigenPodABI)) if err != nil { return nil, fmt.Errorf("failed to load eigenpod abi: %s", err) @@ -275,7 +275,7 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri // fmt.Printf("Checking %d slashed withdrawal addresses for eigenpod status\n", len(allSlashedWithdrawalAddresses)) - slashedEigenpods, err := validEigenpodsOnly(allSlashedWithdrawalAddresses, mc, chainId.Uint64(), eth) + slashedEigenpods, err := validEigenpodsOnly(allSlashedWithdrawalAddresses, mc, chainId.Uint64()) if len(slashedEigenpods) == 0 { log.Println("No eigenpods were slashed.") From 94ce18d59af6d01549dbc42b16c557d5b3570dcf Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 15:58:02 -0500 Subject: [PATCH 14/25] update pipeline --- .github/workflows/cli_release.yml | 45 -------------- .github/workflows/go_test.yml | 32 ---------- .github/workflows/lint.yml | 36 ------------ .github/workflows/pipeline.yml | 97 +++++++++++++++++++++++++++++++ cli/core/findStalePods.go | 10 +++- 5 files changed, 105 insertions(+), 115 deletions(-) delete mode 100644 .github/workflows/cli_release.yml delete mode 100644 .github/workflows/go_test.yml delete mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/pipeline.yml diff --git a/.github/workflows/cli_release.yml b/.github/workflows/cli_release.yml deleted file mode 100644 index 559db094..00000000 --- a/.github/workflows/cli_release.yml +++ /dev/null @@ -1,45 +0,0 @@ -# .github/workflows/release.yml -name: Release CLI Binaries - -on: - pull_request: - push: - # run only against tags - tags: - - "*" - -permissions: - contents: write - -jobs: - goreleaser: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: stable - - name: Run GoReleaser (tagged release) - uses: goreleaser/goreleaser-action@v6 - if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') }} - with: - distribution: goreleaser - version: "~> v2" - args: release --clean - workdir: cli - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Run GoReleaser (branch) - uses: goreleaser/goreleaser-action@v6 - if: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }} - with: - distribution: goreleaser - version: "~> v2" - args: release --snapshot - workdir: cli - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/go_test.yml b/.github/workflows/go_test.yml deleted file mode 100644 index 41500408..00000000 --- a/.github/workflows/go_test.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Run Go Tests - -on: - push: - pull_request: - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: '1.21' - - - name: Install dependencies - run: | - go mod download - sudo apt-get install -y unzip - - - name: Download blockchain data - run: | - curl -o data/deneb_holesky_beacon_state_2227472.ssz.zip https://dviu8zszosyat.cloudfront.net/deneb_holesky_beacon_state_2227472.ssz.zip - (cd data && unzip deneb_holesky_beacon_state_2227472.ssz.zip) - - - name: Run tests - run: | - go test -v ./... diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 7670221c..00000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Lint - -on: - push: - branches: - - main - pull_request: - -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up Go 1.22 - uses: actions/setup-go@v1 - env: - GOPATH: /home/runner/.go - with: - go-version: 1.22.4 - - - name: Install dependencies - env: - GOPATH: /home/runner/.go - run: | - mkdir /home/runner/.go - make setup - go env - ls -lar $GOPATH - - - name: Run Lint - env: - GOPATH: /home/runner/.go - run: /home/runner/.go/bin/golangci-lint run ./cli diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml new file mode 100644 index 00000000..fef624d2 --- /dev/null +++ b/.github/workflows/pipeline.yml @@ -0,0 +1,97 @@ +# .github/workflows/release.yml +name: Release CLI Binaries + +on: + pull_request: + push: + # run only against tags + tags: + - "*" + +permissions: + contents: write + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Go 1.22 + uses: actions/setup-go@v1 + env: + GOPATH: /home/runner/.go + with: + go-version: 1.22.4 + + - name: Install dependencies + env: + GOPATH: /home/runner/.go + run: | + mkdir /home/runner/.go + make setup + go env + ls -lar $GOPATH + + - name: Run Lint + env: + GOPATH: /home/runner/.go + run: /home/runner/.go/bin/golangci-lint run ./cli + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.21' + + - name: Install dependencies + run: | + go mod download + sudo apt-get install -y unzip + + - name: Download blockchain data + run: | + curl -o data/deneb_holesky_beacon_state_2227472.ssz.zip https://dviu8zszosyat.cloudfront.net/deneb_holesky_beacon_state_2227472.ssz.zip + (cd data && unzip deneb_holesky_beacon_state_2227472.ssz.zip) + + - name: Run tests + run: | + go test -v ./... + goreleaser: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: stable + - name: Run GoReleaser (tagged release) + uses: goreleaser/goreleaser-action@v6 + if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') }} + with: + distribution: goreleaser + version: "~> v2" + args: release --clean + workdir: cli + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Run GoReleaser (branch) + uses: goreleaser/goreleaser-action@v6 + if: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }} + with: + distribution: goreleaser + version: "~> v2" + args: release --snapshot + workdir: cli + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/cli/core/findStalePods.go b/cli/core/findStalePods.go index 400f2494..f193f069 100644 --- a/cli/core/findStalePods.go +++ b/cli/core/findStalePods.go @@ -54,7 +54,7 @@ func validEigenpodsOnly(candidateAddresses []common.Address, mc *multicall.Multi podManagerAddress, ok := PodManagerContracts()[chainId] if !ok { - return nil, fmt.Errorf("Unsupported chainId: %d", chainId) + return nil, fmt.Errorf("unsupported chainId: %d", chainId) } ////// step 1: cast all addresses to EigenPod, and attempt to read the pod owner. @@ -117,6 +117,10 @@ func validEigenpodsOnly(candidateAddresses []common.Address, mc *multicall.Multi } authoritativeOwnerToPod, err := multicall.DoMany(mc, authoritativeOwnerToPodCalls...) + if err != nil { + return nil, err + } + nullAddress := common.BigToAddress(big.NewInt(0)) ////// step 3: the valid eigenrestpods are the ones where authoritativeOwnerToPod[i] == candidateAddresses[i]. @@ -274,8 +278,10 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri ) // fmt.Printf("Checking %d slashed withdrawal addresses for eigenpod status\n", len(allSlashedWithdrawalAddresses)) - slashedEigenpods, err := validEigenpodsOnly(allSlashedWithdrawalAddresses, mc, chainId.Uint64()) + if err != nil { + return nil, err + } if len(slashedEigenpods) == 0 { log.Println("No eigenpods were slashed.") From 6ded5158a2f4a61410e68d1344c0b440fbf9bb44 Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 15:58:42 -0500 Subject: [PATCH 15/25] Rename pipeline --- .github/workflows/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index fef624d2..a1101859 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -1,5 +1,5 @@ # .github/workflows/release.yml -name: Release CLI Binaries +name: Build, test, release on: pull_request: From 5b122110bc946f36236234cab4e90eeabfe018d3 Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 16:07:28 -0500 Subject: [PATCH 16/25] fix --- cli/core/findStalePods.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/core/findStalePods.go b/cli/core/findStalePods.go index f193f069..af6c2be2 100644 --- a/cli/core/findStalePods.go +++ b/cli/core/findStalePods.go @@ -190,7 +190,7 @@ func ComputeBalanceDeviationSync(ctx context.Context, eth *ethclient.Client, sta PanicOnError("failed to load pod owner", err) activeShares, err := delegationManager.GetWithdrawableShares(nil, podOwner, []common.Address{ - common.HexToAddress(NATIVE_ETH_STRATEGY), + BeaconStrategy(), }) PanicOnError("failed to load owner shares", err) @@ -200,7 +200,7 @@ func ComputeBalanceDeviationSync(ctx context.Context, eth *ethclient.Client, sta for i, withdrawal := range withdrawalInfo.Withdrawals { for j, strategy := range withdrawal.Strategies { - if strategy.Cmp(common.HexToAddress(NATIVE_ETH_STRATEGY)) == 0 { + if strategy.Cmp(BeaconStrategy()) == 0 { sharesPendingWithdrawal = new(big.Int).Add(sharesPendingWithdrawal, withdrawalInfo.Shares[i][j]) } } From 195663a50f04f1d0e770a4f1e12f2d2e4b8d22eb Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 16:26:54 -0500 Subject: [PATCH 17/25] cap withdrawals taking into account in-flight withdrawals --- cli/commands/queueWithdrawal.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index 247342c6..be87f6ef 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -6,9 +6,12 @@ import ( "fmt" "math/big" + lo "github.com/samber/lo" + "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" ) @@ -58,9 +61,25 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { reg := new(big.Int).SetUint64(_reg) + sumQueuedWithdrawalsGwei := func() *big.Float { + queuedWithdrawals, err := dm.GetQueuedWithdrawals(nil, podOwner) + core.PanicOnError("failed to fetch queued withdrawals", err) + + // calculate the 2d-sum of the `shares` array + return core.WeiToGwei(utils.BigSum(lo.Map(queuedWithdrawals.Shares, func(values []*big.Int, i int) *big.Int { + // return a sum of values. + return lo.Reduce(values, func(accum *big.Int, val *big.Int, idx int) *big.Int { + return new(big.Int).Add(accum, val) + }, big.NewInt(0)) + }))) + }() + + // maximumWithdrawalSizeGwei = reg - gwei(sumQueuedWithdrawals) + maximumWithdrawalSizeGwei := new(big.Float).Sub(new(big.Float).SetInt(reg), sumQueuedWithdrawalsGwei) + requestedWithdrawalSizeWei := func() *big.Int { if args.AmountWei == 0 { - // if AmountWei isn't specified, we withdraw all the shares in the beacon strategy. + // if AmountWei isn't specified, we withdraw: all the shares in the beacon strategy return res.WithdrawableShares[0] } @@ -74,6 +93,10 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { return errors.New("the amount to withdraw is larger than the amount of withdrawable shares in the beacon strategy") } + if requestedWithdrawalSizeGwei.Cmp(maximumWithdrawalSizeGwei) > 0 { + return errors.New("the amount to withdraw is larger than the total withdrawable amount") + } + _depositShares, err := dm.ConvertToDepositShares(nil, podOwner, []common.Address{core.BeaconStrategy()}, []*big.Int{requestedWithdrawalSizeWei}) core.PanicOnError("failed to compute deposit shares", err) depositShares := _depositShares[0] From 46a0174f1a7e32ee338f015e5b652d99883a8e21 Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 16:40:53 -0500 Subject: [PATCH 18/25] fix affordability calc --- cli/commands/completeAllWithdrawals.go | 8 +++++--- cli/commands/queueWithdrawal.go | 5 +---- cli/commands/showWithdrawals.go | 2 ++ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index 38896860..d559d1bc 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -58,6 +58,7 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { reg, err := pod.WithdrawableRestakedExecutionLayerGwei(nil) core.PanicOnError("failed to fetch REG", err) + rew := core.GweiToWei(new(big.Float).SetUint64(reg)) podOwner, err := pod.PodOwner(nil) core.PanicOnError("failed to read podOwner", err) @@ -85,14 +86,15 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { return nil } - var runningSum uint64 = 0 + var runningSumWei uint64 = 0 affordedWithdrawals := lo.Map(eligibleWithdrawals, func(withdrawal *IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { if withdrawal == nil { return nil } withdrawalShares := queuedWithdrawals.Shares[index][0].Uint64() - if reg < (runningSum + withdrawalShares) { - runningSum = runningSum + withdrawalShares + // if REW < runningSumWei + withdrawalShares, we can complete with withdrawal. + if rew.Cmp(new(big.Float).SetUint64(runningSumWei+withdrawalShares)) < 0 { + runningSumWei = runningSumWei + withdrawalShares return withdrawal } return nil diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index be87f6ef..463cb9e6 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -67,10 +67,7 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { // calculate the 2d-sum of the `shares` array return core.WeiToGwei(utils.BigSum(lo.Map(queuedWithdrawals.Shares, func(values []*big.Int, i int) *big.Int { - // return a sum of values. - return lo.Reduce(values, func(accum *big.Int, val *big.Int, idx int) *big.Int { - return new(big.Int).Add(accum, val) - }, big.NewInt(0)) + return utils.BigSum(values) }))) }() diff --git a/cli/commands/showWithdrawals.go b/cli/commands/showWithdrawals.go index 41b4e38e..6f8e58be 100644 --- a/cli/commands/showWithdrawals.go +++ b/cli/commands/showWithdrawals.go @@ -52,6 +52,7 @@ func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { AvailableAfterBlock *big.Int Ready bool TotalAmountETH *big.Float + TotalAmountWei *big.Float } minDelay, err := dm.MinWithdrawalDelayBlocks(nil) @@ -71,6 +72,7 @@ func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { withdrawalInfo = append(withdrawalInfo, TWithdrawalInfo{ TotalAmountETH: core.GweiToEther(core.WeiToGwei(withdrawalTotalValueWei)), + TotalAmountWei: new(big.Float).SetInt(withdrawalTotalValueWei), Strategies: allWithdrawals.Withdrawals[i].Strategies, Staker: allWithdrawals.Withdrawals[i].Staker.Hex(), AvailableAfterBlock: targetBlock, From 2ce1119a242f90665f381d34034cdf26ee170fe6 Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 16:41:55 -0500 Subject: [PATCH 19/25] fix typo --- cli/commands/completeAllWithdrawals.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index d559d1bc..6b0ab3f0 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -116,7 +116,7 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { } fmt.Printf("Your podOwner(%s) has %d withdrawals that can be completed right now.\n", podOwner.Hex(), len(affordedWithdrawals)) - fmt.Printf("Total ETH: %sETH\n", core.GweiToEther(core.WeiToGwei(new(big.Int).SetUint64(runningSum))).String()) + fmt.Printf("Total ETH: %sETH\n", core.GweiToEther(core.WeiToGwei(new(big.Int).SetUint64(runningSumWei))).String()) if !isSimulation { core.PanicIfNoConsent("Would you like to continue?") From e27102935169024003da5f3bf271e7e57fb0bedd Mon Sep 17 00:00:00 2001 From: gpsanant Date: Wed, 18 Dec 2024 14:14:46 -0800 Subject: [PATCH 20/25] fix: cleanup show withdrawals --- cli/commands/completeAllWithdrawals.go | 2 +- cli/commands/showWithdrawals.go | 37 +++++++++----------------- cli/core/utils.go | 16 ++++++++--- 3 files changed, 26 insertions(+), 29 deletions(-) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index 6b0ab3f0..9cc81a22 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -74,7 +74,7 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { eligibleWithdrawals := lo.Map(queuedWithdrawals.Withdrawals, func(withdrawal IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { isBeaconWithdrawal := len(withdrawal.Strategies) == 1 && withdrawal.Strategies[0].Cmp(core.BeaconStrategy()) == 0 - isExecutable := curBlockNumber >= uint64(withdrawal.StartBlock+minDelay) + isExecutable := curBlockNumber > uint64(withdrawal.StartBlock+minDelay) if isBeaconWithdrawal && isExecutable { return &withdrawal } diff --git a/cli/commands/showWithdrawals.go b/cli/commands/showWithdrawals.go index 6f8e58be..943b4faa 100644 --- a/cli/commands/showWithdrawals.go +++ b/cli/commands/showWithdrawals.go @@ -3,9 +3,6 @@ package commands import ( "context" "math/big" - "time" - - lo "github.com/samber/lo" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" @@ -15,24 +12,18 @@ import ( type TShowWithdrawalArgs struct { EthNode string - BeaconNode string EigenPod string Strategies common.Address } func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { ctx := context.Background() - eth, _, chainId, err := core.GetClients(ctx, args.EthNode, args.BeaconNode, false /* isVerbose */) + eth, chainId, err := core.GetEthClient(ctx, args.EthNode) core.PanicOnError("failed to reach eth and beacon node", err) curBlock, err := eth.BlockByNumber(ctx, nil) /* head */ core.PanicOnError("failed to load curBlock", err) - genBlock, err := eth.BlockByNumber(ctx, big.NewInt(0)) /* head */ - core.PanicOnError("failed to load genesis block", err) - - timePerBlockSeconds := float64(curBlock.NumberU64()-genBlock.NumberU64()) / float64(curBlock.Time()-genBlock.Time()) - dm, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) core.PanicOnError("failed to reach delegation manager", err) @@ -47,12 +38,11 @@ func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { type TWithdrawalInfo struct { Staker string - Strategies []common.Address - AvailableAfter string + Strategy common.Address + CurrentBlock uint64 AvailableAfterBlock *big.Int Ready bool TotalAmountETH *big.Float - TotalAmountWei *big.Float } minDelay, err := dm.MinWithdrawalDelayBlocks(nil) @@ -61,23 +51,22 @@ func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { withdrawalInfo := []TWithdrawalInfo{} for i, shares := range allWithdrawals.Shares { - withdrawalTotalValueWei := lo.Reduce(shares, func(accum *big.Int, item *big.Int, i int) *big.Int { - return new(big.Int).Add(item, accum) - }, big.NewInt(0)) + withdrawal := allWithdrawals.Withdrawals[i] - targetBlock := new(big.Int).SetUint64(uint64(allWithdrawals.Withdrawals[i].StartBlock + minDelay)) + // this cli is only for withdrawals of beaconstrategy for a single strategy + if withdrawal.Strategies[0].Cmp(core.BeaconStrategy()) != 0 || len(withdrawal.Strategies) != 1 { + continue + } - blockDeltaSeconds := (targetBlock.Uint64() - curBlock.NumberU64()) * uint64(timePerBlockSeconds) - availableAfter := time.Now().Add(time.Second * time.Duration(blockDeltaSeconds)) + targetBlock := new(big.Int).SetUint64(uint64(allWithdrawals.Withdrawals[i].StartBlock + minDelay)) withdrawalInfo = append(withdrawalInfo, TWithdrawalInfo{ - TotalAmountETH: core.GweiToEther(core.WeiToGwei(withdrawalTotalValueWei)), - TotalAmountWei: new(big.Float).SetInt(withdrawalTotalValueWei), - Strategies: allWithdrawals.Withdrawals[i].Strategies, + TotalAmountETH: core.GweiToEther(core.WeiToGwei(shares[0])), + Strategy: allWithdrawals.Withdrawals[i].Strategies[0], Staker: allWithdrawals.Withdrawals[i].Staker.Hex(), + CurrentBlock: curBlock.NumberU64(), AvailableAfterBlock: targetBlock, - AvailableAfter: availableAfter.String(), - Ready: targetBlock.Uint64() <= curBlock.NumberU64(), + Ready: targetBlock.Uint64() < curBlock.NumberU64(), }) } diff --git a/cli/core/utils.go b/cli/core/utils.go index 0cf0cc63..34a55930 100644 --- a/cli/core/utils.go +++ b/cli/core/utils.go @@ -430,19 +430,27 @@ func ForkVersions() map[uint64]string { } } -func GetClients(ctx context.Context, node, beaconNodeUri string, enableLogs bool) (*ethclient.Client, BeaconClient, *big.Int, error) { +func GetEthClient(ctx context.Context, node string) (*ethclient.Client, *big.Int, error) { eth, err := ethclient.Dial(node) if err != nil { - return nil, nil, nil, fmt.Errorf("failed to reach eth --node: %w", err) + return nil, nil, fmt.Errorf("failed to reach eth --node: %w", err) } chainId, err := eth.ChainID(ctx) if err != nil { - return nil, nil, nil, fmt.Errorf("failed to fetch chain id: %w", err) + return nil, nil, fmt.Errorf("failed to fetch chain id: %w", err) } if chainId == nil || (chainId.Int64() != 17000 && chainId.Int64() != 1) { - return nil, nil, nil, errors.New("this tool only supports the Holesky and Mainnet Ethereum Networks") + return nil, nil, errors.New("this tool only supports the Holesky and Mainnet Ethereum Networks") + } + return eth, chainId, nil +} + +func GetClients(ctx context.Context, node, beaconNodeUri string, enableLogs bool) (*ethclient.Client, BeaconClient, *big.Int, error) { + eth, chainId, err := GetEthClient(ctx, node) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to reach eth --node: %w", err) } beaconClient, err := GetBeaconClient(beaconNodeUri, enableLogs) From d2a8aa68c7029bde36cad1b56404ca7cb4f0eed0 Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 17:24:16 -0500 Subject: [PATCH 21/25] save queueWithdrawal --- cli/commands/queueWithdrawal.go | 47 +++++++++++++++------------------ 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index 463cb9e6..8cdc41dd 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -6,14 +6,12 @@ import ( "fmt" "math/big" - lo "github.com/samber/lo" - "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" - "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" + "github.com/fatih/color" ) type TQueueWithdrawallArgs struct { @@ -61,22 +59,12 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { reg := new(big.Int).SetUint64(_reg) - sumQueuedWithdrawalsGwei := func() *big.Float { - queuedWithdrawals, err := dm.GetQueuedWithdrawals(nil, podOwner) - core.PanicOnError("failed to fetch queued withdrawals", err) - - // calculate the 2d-sum of the `shares` array - return core.WeiToGwei(utils.BigSum(lo.Map(queuedWithdrawals.Shares, func(values []*big.Int, i int) *big.Int { - return utils.BigSum(values) - }))) - }() - - // maximumWithdrawalSizeGwei = reg - gwei(sumQueuedWithdrawals) - maximumWithdrawalSizeGwei := new(big.Float).Sub(new(big.Float).SetInt(reg), sumQueuedWithdrawalsGwei) + // TODO: maximumWithdrawalSizeGwei = reg - gwei(sumQueuedWithdrawals) + maximumWithdrawalSizeGwei := new(big.Float).SetInt(reg) requestedWithdrawalSizeWei := func() *big.Int { if args.AmountWei == 0 { - // if AmountWei isn't specified, we withdraw: all the shares in the beacon strategy + // default to the number of withdrawable shares in the beacon strategy return res.WithdrawableShares[0] } @@ -87,11 +75,23 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { if requestedWithdrawalSizeGwei.Cmp(new(big.Float).SetInt(res.WithdrawableShares[0])) > 0 { // requested to withdraw too many shares. - return errors.New("the amount to withdraw is larger than the amount of withdrawable shares in the beacon strategy") + color.Yellow( + "Warning: the amount to withdraw from the beacon strategy (%sETH) is larger than the amount of withdrawable shares (%sETH) in the beacon strategy\n", + core.GweiToEther(requestedWithdrawalSizeGwei).String(), + core.GweiToEther(maximumWithdrawalSizeGwei).String(), + ) + requestedWithdrawalSizeWei, _ = core.GweiToWei(maximumWithdrawalSizeGwei).Int(nil) + *requestedWithdrawalSizeGwei = *maximumWithdrawalSizeGwei } if requestedWithdrawalSizeGwei.Cmp(maximumWithdrawalSizeGwei) > 0 { - return errors.New("the amount to withdraw is larger than the total withdrawable amount") + color.Yellow( + "Warning: the amount to withdraw from the native ETH strategy (%sETH) is larger than the total withdrawable amount from the pod (%sETH). Will attempt a smaller withdrawal.\n", + core.GweiToEther(requestedWithdrawalSizeGwei).String(), + core.GweiToEther(maximumWithdrawalSizeGwei).String(), + ) + requestedWithdrawalSizeWei, _ = core.GweiToWei(maximumWithdrawalSizeGwei).Int(nil) + *requestedWithdrawalSizeGwei = *maximumWithdrawalSizeGwei } _depositShares, err := dm.ConvertToDepositShares(nil, podOwner, []common.Address{core.BeaconStrategy()}, []*big.Int{requestedWithdrawalSizeWei}) @@ -109,14 +109,9 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { var amountToWithdrawDepositSharesGwei *big.Int = new(big.Int) *amountToWithdrawDepositSharesGwei = *depositSharesGwei - fmt.Printf("In the Native ETH strategy, you have %sETH to be withdrawn.\n", core.GweiToEther(new(big.Float).SetInt(depositSharesGwei))) - fmt.Printf("NOTE: If you were or become slashed on EigenLayer during the withdrawal period, the total amount received will be less any slashed amount.\n") - - if depositSharesGwei.Cmp(reg) > 0 { - fmt.Printf("Queueing a partial withdrawal. Your pod only had %sETH available to satisfy withdrawals.", core.GweiToEther(new(big.Float).SetInt(reg)).String()) - fmt.Printf("Checkpointing may update this balance, if you have any uncheckpointed native eth or beacon rewards.") - *amountToWithdrawDepositSharesGwei = *reg - } + requestedWithdrawalSizeEth := core.GweiToEther(core.WeiToGwei(requestedWithdrawalSizeWei)) + color.Blue("Withdrawing: %sETH.\n", requestedWithdrawalSizeEth.String()) + color.Yellow("NOTE: If you were or become slashed on EigenLayer during the withdrawal period, the total amount received will be less any slashed amount.\n") if !isSimulation { core.PanicIfNoConsent(fmt.Sprintf("Would you like to queue a withdrawal %sETH from the Native ETH strategy? This will be withdrawable after approximately block #%d (current block: %d)\n", core.GweiToEther(new(big.Float).SetInt(amountToWithdrawDepositSharesGwei)), curBlock+uint64(minWithdrawalDelay), curBlock)) From f78a8ebce13cbc96d1ccdc214b69553d86608bcf Mon Sep 17 00:00:00 2001 From: gpsanant Date: Wed, 18 Dec 2024 14:29:12 -0800 Subject: [PATCH 22/25] chore: logs --- cli/commands/completeAllWithdrawals.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index 9cc81a22..830d5fa4 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -74,8 +74,8 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { eligibleWithdrawals := lo.Map(queuedWithdrawals.Withdrawals, func(withdrawal IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { isBeaconWithdrawal := len(withdrawal.Strategies) == 1 && withdrawal.Strategies[0].Cmp(core.BeaconStrategy()) == 0 - isExecutable := curBlockNumber > uint64(withdrawal.StartBlock+minDelay) - if isBeaconWithdrawal && isExecutable { + isCompletable := curBlockNumber > uint64(withdrawal.StartBlock+minDelay) + if isBeaconWithdrawal && isCompletable { return &withdrawal } return nil @@ -92,6 +92,12 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { return nil } withdrawalShares := queuedWithdrawals.Shares[index][0].Uint64() + + fmt.Println("runningSumWei", runningSumWei) + fmt.Println("withdrawalShares", withdrawalShares) + fmt.Println("rew", rew) + fmt.Println("runningSumWei + withdrawalShares", new(big.Float).SetUint64(runningSumWei+withdrawalShares)) + fmt.Println("rew.Cmp(new(big.Float).SetUint64(runningSumWei+withdrawalShares))", rew.Cmp(new(big.Float).SetUint64(runningSumWei+withdrawalShares))) // if REW < runningSumWei + withdrawalShares, we can complete with withdrawal. if rew.Cmp(new(big.Float).SetUint64(runningSumWei+withdrawalShares)) < 0 { runningSumWei = runningSumWei + withdrawalShares From ec66f13bc6ae08241650b60940d618f15063387d Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 17:42:41 -0500 Subject: [PATCH 23/25] fix complete all withdrawals --- cli/commands/completeAllWithdrawals.go | 31 +++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index 830d5fa4..b6c7afe9 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -86,21 +86,21 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { return nil } - var runningSumWei uint64 = 0 + var runningSumWei *big.Float = new(big.Float) + affordedWithdrawals := lo.Map(eligibleWithdrawals, func(withdrawal *IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { if withdrawal == nil { return nil } - withdrawalShares := queuedWithdrawals.Shares[index][0].Uint64() - - fmt.Println("runningSumWei", runningSumWei) - fmt.Println("withdrawalShares", withdrawalShares) - fmt.Println("rew", rew) - fmt.Println("runningSumWei + withdrawalShares", new(big.Float).SetUint64(runningSumWei+withdrawalShares)) - fmt.Println("rew.Cmp(new(big.Float).SetUint64(runningSumWei+withdrawalShares))", rew.Cmp(new(big.Float).SetUint64(runningSumWei+withdrawalShares))) - // if REW < runningSumWei + withdrawalShares, we can complete with withdrawal. - if rew.Cmp(new(big.Float).SetUint64(runningSumWei+withdrawalShares)) < 0 { - runningSumWei = runningSumWei + withdrawalShares + withdrawalShares := queuedWithdrawals.Shares[index][0] + // if REW > runningSumWei + withdrawalShares, we can complete with withdrawal. + if rew.Cmp( + new(big.Float).Add( + runningSumWei, + new(big.Float).SetInt(withdrawalShares), + ), + ) > 0 { + runningSumWei = runningSumWei.Add(runningSumWei, new(big.Float).SetInt(withdrawalShares)) return withdrawal } return nil @@ -111,18 +111,19 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { }) if len(affordedWithdrawals) == 0 && len(eligibleWithdrawals) > 0 { - fmt.Printf("WARN: Your pod has %d withdrawals available, but your pod does not have enough funding to proceed.\n", len(eligibleWithdrawals)) + fmt.Printf("WARN: Your pod has %d withdrawal(s) available, but your pod does not have enough funding to proceed.\n", len(eligibleWithdrawals)) fmt.Printf("Consider checkpointing to claim beacon rewards, or depositing ETH and checkpointing to complete these withdrawals.\n\n") return errors.New("Insufficient funds") } if len(affordedWithdrawals) != len(eligibleWithdrawals) { - fmt.Printf("WARN: Your pod has %d withdrawals available, but you only have enough balance to satisfy %d of them.\n", len(eligibleWithdrawals), len(affordedWithdrawals)) + fmt.Printf("WARN: Your pod has %d withdrawal(s) available, but you only have enough balance to satisfy %d of them.\n", len(eligibleWithdrawals), len(affordedWithdrawals)) fmt.Printf("Consider checkpointing to claim beacon rewards, or depositing ETH and checkpointing to complete these withdrawals.\n\n") } - fmt.Printf("Your podOwner(%s) has %d withdrawals that can be completed right now.\n", podOwner.Hex(), len(affordedWithdrawals)) - fmt.Printf("Total ETH: %sETH\n", core.GweiToEther(core.WeiToGwei(new(big.Int).SetUint64(runningSumWei))).String()) + fmt.Printf("Your podOwner(%s) has %d withdrawal(s) that can be completed right now.\n", podOwner.Hex(), len(affordedWithdrawals)) + runningSumWeiInt, _ := runningSumWei.Int(nil) + fmt.Printf("Total ETH on all withdrawals: %sETH\n", core.GweiToEther(core.WeiToGwei(runningSumWeiInt)).String()) if !isSimulation { core.PanicIfNoConsent("Would you like to continue?") From ac02b41b64919b85845ed587306769a95b553d44 Mon Sep 17 00:00:00 2001 From: gpsanant Date: Wed, 18 Dec 2024 14:49:13 -0800 Subject: [PATCH 24/25] fix: make queuing work? --- cli/commands/queueWithdrawal.go | 53 ++++++++++----------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index 8cdc41dd..b7788c3f 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -54,44 +54,26 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { podOwner, err := pod.PodOwner(nil) core.PanicOnError("failed to read podOwner", err) - res, err := dm.GetWithdrawableShares(nil, podOwner, []common.Address{core.BeaconStrategy()}) - core.PanicOnError("failed to read beacon strategy withdrawable shares", err) - reg := new(big.Int).SetUint64(_reg) // TODO: maximumWithdrawalSizeGwei = reg - gwei(sumQueuedWithdrawals) - maximumWithdrawalSizeGwei := new(big.Float).SetInt(reg) - - requestedWithdrawalSizeWei := func() *big.Int { - if args.AmountWei == 0 { - // default to the number of withdrawable shares in the beacon strategy - return res.WithdrawableShares[0] - } - + maximumWithdrawalSizeWei := core.IGweiToWei(reg) + var requestedWithdrawalSizeWei *big.Int + if args.AmountWei == 0 { + // default to the number of withdrawable shares in the beacon strategy + requestedWithdrawalSizeWei = maximumWithdrawalSizeWei + } else { // if it is specified, we withdraw the specific amount. - return new(big.Int).SetUint64(args.AmountWei) - }() - requestedWithdrawalSizeGwei := core.WeiToGwei(requestedWithdrawalSizeWei) - - if requestedWithdrawalSizeGwei.Cmp(new(big.Float).SetInt(res.WithdrawableShares[0])) > 0 { - // requested to withdraw too many shares. - color.Yellow( - "Warning: the amount to withdraw from the beacon strategy (%sETH) is larger than the amount of withdrawable shares (%sETH) in the beacon strategy\n", - core.GweiToEther(requestedWithdrawalSizeGwei).String(), - core.GweiToEther(maximumWithdrawalSizeGwei).String(), - ) - requestedWithdrawalSizeWei, _ = core.GweiToWei(maximumWithdrawalSizeGwei).Int(nil) - *requestedWithdrawalSizeGwei = *maximumWithdrawalSizeGwei + requestedWithdrawalSizeWei = new(big.Int).SetUint64(args.AmountWei) } - if requestedWithdrawalSizeGwei.Cmp(maximumWithdrawalSizeGwei) > 0 { - color.Yellow( - "Warning: the amount to withdraw from the native ETH strategy (%sETH) is larger than the total withdrawable amount from the pod (%sETH). Will attempt a smaller withdrawal.\n", - core.GweiToEther(requestedWithdrawalSizeGwei).String(), - core.GweiToEther(maximumWithdrawalSizeGwei).String(), + if requestedWithdrawalSizeWei.Cmp(maximumWithdrawalSizeWei) > 0 { + color.Red( + "Error: the amount to withdraw from the native ETH strategy (%sETH) is larger than the total withdrawable amount from the pod (%sETH). Will attempt a smaller withdrawal.\n", + core.IweiToEther(requestedWithdrawalSizeWei).String(), + core.IweiToEther(maximumWithdrawalSizeWei).String(), ) - requestedWithdrawalSizeWei, _ = core.GweiToWei(maximumWithdrawalSizeGwei).Int(nil) - *requestedWithdrawalSizeGwei = *maximumWithdrawalSizeGwei + return errors.New("requested to withdraw too many shares") } _depositShares, err := dm.ConvertToDepositShares(nil, podOwner, []common.Address{core.BeaconStrategy()}, []*big.Int{requestedWithdrawalSizeWei}) @@ -104,24 +86,19 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { curBlock, err := eth.BlockNumber(ctx) core.PanicOnError("failed to load current block number", err) - depositSharesGwei := core.IGweiToWei(depositShares) - - var amountToWithdrawDepositSharesGwei *big.Int = new(big.Int) - *amountToWithdrawDepositSharesGwei = *depositSharesGwei - requestedWithdrawalSizeEth := core.GweiToEther(core.WeiToGwei(requestedWithdrawalSizeWei)) color.Blue("Withdrawing: %sETH.\n", requestedWithdrawalSizeEth.String()) color.Yellow("NOTE: If you were or become slashed on EigenLayer during the withdrawal period, the total amount received will be less any slashed amount.\n") if !isSimulation { - core.PanicIfNoConsent(fmt.Sprintf("Would you like to queue a withdrawal %sETH from the Native ETH strategy? This will be withdrawable after approximately block #%d (current block: %d)\n", core.GweiToEther(new(big.Float).SetInt(amountToWithdrawDepositSharesGwei)), curBlock+uint64(minWithdrawalDelay), curBlock)) + core.PanicIfNoConsent(fmt.Sprintf("Would you like to queue a withdrawal %sETH from the Native ETH strategy? This will be withdrawable after approximately block #%d (current block: %d)\n", requestedWithdrawalSizeEth.String(), curBlock+uint64(minWithdrawalDelay), curBlock)) } else { fmt.Printf("THIS IS A SIMULATION. No transaction will be recorded onchain.\n") } txn, err := dm.QueueWithdrawals(acc.TransactionOptions, []IDelegationManager.IDelegationManagerTypesQueuedWithdrawalParams{ { Strategies: []common.Address{core.BeaconStrategy()}, - DepositShares: []*big.Int{core.IGweiToWei(amountToWithdrawDepositSharesGwei)}, + DepositShares: []*big.Int{depositShares}, Withdrawer: podOwner, }, }) From 7fe165d26be4f954ca86a987d6dc75fe15cb8e7a Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 18:15:14 -0500 Subject: [PATCH 25/25] fully tested --- cli/commands/completeAllWithdrawals.go | 29 +++++++++++++++++--------- cli/commands/queueWithdrawal.go | 5 ++++- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index b6c7afe9..9399f0dc 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -11,8 +11,10 @@ import ( "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" + "github.com/fatih/color" ) type TCompleteWithdrawalArgs struct { @@ -81,7 +83,11 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { return nil }) - if len(eligibleWithdrawals) == 0 { + readyWithdrawalCount := len(lo.Filter(eligibleWithdrawals, func(withdrawal *IDelegationManager.IDelegationManagerTypesWithdrawal, index int) bool { + return withdrawal != nil + })) + + if readyWithdrawalCount == 0 { fmt.Printf("Your pod has no eligible withdrawals.\n") return nil } @@ -100,7 +106,7 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { new(big.Float).SetInt(withdrawalShares), ), ) > 0 { - runningSumWei = runningSumWei.Add(runningSumWei, new(big.Float).SetInt(withdrawalShares)) + runningSumWei = new(big.Float).Add(runningSumWei, new(big.Float).SetInt(withdrawalShares)) return withdrawal } return nil @@ -110,15 +116,15 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { return withdrawal != nil }) - if len(affordedWithdrawals) == 0 && len(eligibleWithdrawals) > 0 { - fmt.Printf("WARN: Your pod has %d withdrawal(s) available, but your pod does not have enough funding to proceed.\n", len(eligibleWithdrawals)) - fmt.Printf("Consider checkpointing to claim beacon rewards, or depositing ETH and checkpointing to complete these withdrawals.\n\n") + if len(affordedWithdrawals) == 0 && readyWithdrawalCount > 0 { + color.Yellow("WARN: Your pod has %d withdrawal(s) available, but your pod does not have enough funding to proceed.\n", readyWithdrawalCount) + color.Yellow("Consider checkpointing to claim beacon rewards, or depositing ETH and checkpointing to complete these withdrawals.\n\n") return errors.New("Insufficient funds") } - if len(affordedWithdrawals) != len(eligibleWithdrawals) { - fmt.Printf("WARN: Your pod has %d withdrawal(s) available, but you only have enough balance to satisfy %d of them.\n", len(eligibleWithdrawals), len(affordedWithdrawals)) - fmt.Printf("Consider checkpointing to claim beacon rewards, or depositing ETH and checkpointing to complete these withdrawals.\n\n") + if len(affordedWithdrawals) != readyWithdrawalCount { + color.Yellow("WARN: Your pod has %d withdrawal(s) available, but you only have enough balance to satisfy %d of them.\n", readyWithdrawalCount, len(affordedWithdrawals)) + color.Yellow("Consider checkpointing to claim beacon rewards, or depositing ETH and checkpointing to complete these withdrawals.\n\n") } fmt.Printf("Your podOwner(%s) has %d withdrawal(s) that can be completed right now.\n", podOwner.Hex(), len(affordedWithdrawals)) @@ -128,7 +134,7 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { if !isSimulation { core.PanicIfNoConsent("Would you like to continue?") } else { - fmt.Printf("THIS IS A SIMULATION. No transaction will be recorded onchain.\n") + color.Yellow("THIS IS A SIMULATION. No transaction will be recorded onchain.\n") } withdrawals := lo.Map(affordedWithdrawals, func(w *IDelegationManager.IDelegationManagerTypesWithdrawal, i int) IDelegationManager.IDelegationManagerTypesWithdrawal { @@ -147,7 +153,10 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { core.PanicOnError("CompleteQueuedWithdrawals failed.", err) if !isSimulation { - fmt.Printf("%s\n", txn.Hash().Hex()) + _, err := bind.WaitMined(ctx, eth, txn) + core.PanicOnError("waitMined failed", err) + + color.Green("%s\n", txn.Hash().Hex()) } else { printAsJSON(Transaction{ Type: "complete-withdrawals", diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index b7788c3f..eeaed4f2 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -9,6 +9,7 @@ import ( "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/fatih/color" @@ -104,7 +105,9 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { }) core.PanicOnError("failed to queue withdrawal", err) if !isSimulation { - fmt.Printf("%s\n", txn.Hash().Hex()) + txnReceipt, err := bind.WaitMined(ctx, eth, txn) + core.PanicOnError("failed to wait for txn", err) + color.Green("%s\n", txnReceipt.TxHash.Hex()) } else { printAsJSON(Transaction{ Type: "queue-withdrawal",