From 78a4ff881a479f0f8adda501e7fe95ef2819406f Mon Sep 17 00:00:00 2001 From: Justin Brower Date: Wed, 18 Dec 2024 14:26:04 -0500 Subject: [PATCH] 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 ef0140f..1712822 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 04e9f19..9a39a9d 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 b8c03d7..3a01af3 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 5a848e9..b6fe1b8 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 1e49bd0..560241c 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 e27c188..5c73e8d 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=