Skip to content

Commit

Permalink
Save
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrower95 committed Sep 18, 2024
1 parent 4d2acbd commit 687154d
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 58 deletions.
134 changes: 78 additions & 56 deletions cli/commands/computeCheckpointableValue.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)

type TComputeCheckpointableValueCommandArgs struct {
Expand All @@ -29,67 +30,36 @@ func PodManagerContracts() map[uint64]string {
}
}

//go:embed multicallAbi.json
var multicallAbi string

func ComputeCheckpointableValueCommand(args TComputeCheckpointableValueCommandArgs) error {
ctx := context.Background()

eigenpodAbi, err := abi.JSON(strings.NewReader(onchain.EigenPodABI))
core.PanicOnError("failed to load eigenpod abi", err)

podManagerAbi, err := abi.JSON(strings.NewReader(onchain.EigenPodManagerABI))
core.PanicOnError("failed to load eigenpod manager abi", err)

eth, beaconClient, chainId, err := core.GetClients(ctx, args.Node, args.BeaconNode, true)
core.PanicOnError("failed to reach ethereum clients", err)

podManagerAddress, ok := PodManagerContracts()[chainId.Uint64()]
if !ok {
core.Panic("unsupported network")
}

// fetch latest beacon state.
beaconState, err := beaconClient.GetBeaconState(ctx, "head")
core.PanicOnError("failed to load beacon state", err)

allBalances, err := beaconState.ValidatorBalances()
core.PanicOnError("failed to parse beacon balances", err)

_allValidators, err := beaconState.Validators()
core.PanicOnError("failed to fetch validators", err)
allValidators := utils.Map(_allValidators, func(validator *phase0.Validator, i uint64) core.ValidatorWithIndex {
return core.ValidatorWithIndex{
Validator: validator,
Index: i,
}
})
type TQueryAllEigenpodsOnNetworkArgs struct {
Ctx context.Context
AllValidators []core.ValidatorWithIndex
Eth *ethclient.Client
EigenpodAbi abi.ABI
PodManagerAbi abi.ABI
PodManagerAddress string
Mc *multicall.MulticallClient
}

func queryAllEigenpodsOnNetwork(args TQueryAllEigenpodsOnNetworkArgs) ([]string, error) {
// see which validators are eigenpods
//
// 1. can ignore anything that isn't withdrawing to the execution chain.
executionLayerWithdrawalCredentialValidators := utils.Filter(allValidators, func(validator core.ValidatorWithIndex) bool {
executionLayerWithdrawalCredentialValidators := utils.Filter(args.AllValidators, func(validator core.ValidatorWithIndex) bool {
return validator.Validator.WithdrawalCredentials[0] == 1
})

// multicall request a bunch of different validators to check whether they're eigenpods
mc, err := multicall.NewMulticallClient(ctx, eth, &multicall.TMulticallClientOptions{
MaxBatchSizeBytes: 8192,
})
core.PanicOnError("error initializing mc", err)

interestingWithdrawalAddresses := getKeys(utils.Reduce(executionLayerWithdrawalCredentialValidators, func(accum map[string]int, next core.ValidatorWithIndex) map[string]int {
accum[common.Bytes2Hex(next.Validator.WithdrawalCredentials[12:])] = 1
return accum
}, map[string]int{}))

fmt.Printf("Querying %d addresses to see if they may be eigenpods\n", len(interestingWithdrawalAddresses))
podOwners, err := multicall.DoMultiCallManyReportingFailures[*common.Address](*mc, utils.Map(interestingWithdrawalAddresses, func(address string, index uint64) *multicall.MultiCallMetaData[*common.Address] {
podOwners, err := multicall.DoMultiCallManyReportingFailures[*common.Address](*args.Mc, utils.Map(interestingWithdrawalAddresses, func(address string, index uint64) *multicall.MultiCallMetaData[*common.Address] {
callMeta, err := multicall.MultiCall(
common.HexToAddress(address),
eigenpodAbi,
args.EigenpodAbi,
func(data []byte) (*common.Address, error) {
res, err := eigenpodAbi.Unpack("podOwner", data)
res, err := args.EigenpodAbi.Unpack("podOwner", data)
if err != nil {
return nil, err
}
Expand All @@ -103,7 +73,7 @@ func ComputeCheckpointableValueCommand(args TComputeCheckpointableValueCommandAr
if podOwners == nil || err != nil || len(*podOwners) == 0 {
core.PanicOnError("failed to fetch podOwners", err)
core.Panic("loaded no pod owners")
return err
return nil, err
}

// now we can filter by which addresses actually claimed to have podOwner()
Expand All @@ -119,18 +89,17 @@ func ComputeCheckpointableValueCommand(args TComputeCheckpointableValueCommandAr
printAsJSON(podToPodOwner)

// array[eigenpods given the owner]
fmt.Printf("Querying %d addresses (podMan=%s) to see if it knows about these eigenpods\n", len(addressesWithPodOwners), podManagerAddress)
fmt.Printf("Querying %d addresses (podMan=%s) to see if it knows about these eigenpods\n", len(addressesWithPodOwners), args.PodManagerAddress)

printAsJSON(podManagerAbi.Methods)
eigenpodForOwner, err := multicall.DoMultiCallManyReportingFailures(
*mc,
*args.Mc,
utils.Map(addressesWithPodOwners, func(address string, i uint64) *multicall.MultiCallMetaData[*common.Address] {
claimedOwner := *podToPodOwner[address]
call, err := multicall.MultiCall(
common.HexToAddress(podManagerAddress),
podManagerAbi,
common.HexToAddress(args.PodManagerAddress),
args.PodManagerAbi,
func(data []byte) (*common.Address, error) {
res, err := podManagerAbi.Unpack("ownerToPod", data)
res, err := args.PodManagerAbi.Unpack("ownerToPod", data)
if err != nil {
return nil, err
}
Expand All @@ -146,9 +115,62 @@ func ComputeCheckpointableValueCommand(args TComputeCheckpointableValueCommandAr
core.PanicOnError("failed to query", err)

// now, see which of `addressesWithPodOwners` properly were eigenpods.
allEigenpods := utils.FilterI(addressesWithPodOwners, func(address string, i uint64) bool {
return utils.FilterI(addressesWithPodOwners, func(address string, i uint64) bool {
return (*eigenpodForOwner)[i].Success && (*eigenpodForOwner)[i].Value.Cmp(common.HexToAddress(addressesWithPodOwners[i])) == 0
}), nil
}

//go:embed multicallAbi.json

Check failure on line 123 in cli/commands/computeCheckpointableValue.go

View workflow job for this annotation

GitHub Actions / test

pattern multicallAbi.json: no matching files found

Check failure on line 123 in cli/commands/computeCheckpointableValue.go

View workflow job for this annotation

GitHub Actions / test

pattern multicallAbi.json: no matching files found
var multicallAbi string

func ComputeCheckpointableValueCommand(args TComputeCheckpointableValueCommandArgs) error {
ctx := context.Background()

eigenpodAbi, err := abi.JSON(strings.NewReader(onchain.EigenPodABI))
core.PanicOnError("failed to load eigenpod abi", err)

podManagerAbi, err := abi.JSON(strings.NewReader(onchain.EigenPodManagerABI))
core.PanicOnError("failed to load eigenpod manager abi", err)

eth, beaconClient, chainId, err := core.GetClients(ctx, args.Node, args.BeaconNode, true)
core.PanicOnError("failed to reach ethereum clients", err)

mc, err := multicall.NewMulticallClient(ctx, eth, &multicall.TMulticallClientOptions{
MaxBatchSizeBytes: 8192,
})
core.PanicOnError("error initializing mc", err)

podManagerAddress, ok := PodManagerContracts()[chainId.Uint64()]
if !ok {
core.Panic("unsupported network")
}

// fetch latest beacon state.
beaconState, err := beaconClient.GetBeaconState(ctx, "head")
core.PanicOnError("failed to load beacon state", err)

allBalances, err := beaconState.ValidatorBalances()
core.PanicOnError("failed to parse beacon balances", err)

_allValidators, err := beaconState.Validators()
core.PanicOnError("failed to fetch validators", err)
allValidators := utils.Map(_allValidators, func(validator *phase0.Validator, i uint64) core.ValidatorWithIndex {
return core.ValidatorWithIndex{
Validator: validator,
Index: i,
}
})

allEigenpods, err := queryAllEigenpodsOnNetwork(TQueryAllEigenpodsOnNetworkArgs{
Ctx: ctx,
AllValidators: allValidators,
Eth: eth,
EigenpodAbi: eigenpodAbi,
PodManagerAbi: podManagerAbi,
PodManagerAddress: podManagerAddress,
Mc: mc,
})

isEigenpodSet := utils.Reduce(allEigenpods, func(allEigenpodSet map[string]int, eigenpod string) map[string]int {
allEigenpodSet[eigenpod] = 1
return allEigenpodSet
Expand All @@ -161,12 +183,12 @@ func ComputeCheckpointableValueCommand(args TComputeCheckpointableValueCommandAr
// now, determine their pending checkpoint rewards per checkpoint
pendingRewardsWeiPerEigenpod := map[string]*big.Int{}

// TODO: compute pending rewards per eigenpod;
// Compute all pending rewards for each eigenpod;
// see: https://github.com/Layr-Labs/eigenlayer-contracts/blob/dev/src/contracts/pods/EigenPod.sol#L656
// return (podBalanceGwei + checkpoint.balanceDeltasGwei)
//
// where
// allRewards(eigenpod) := (podBalanceGwei + checkpoint.balanceDeltasGwei)
//
// where:
// podBalanceGwei = address(pod).balanceGwei - pod.withdrawableRestakedExecutionLayerGwei
// and
// checkpoint.balanceDeltasGwei = sumBeaconBalancesGwei - sumRestakedBalancesGwei
Expand Down
5 changes: 3 additions & 2 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ func main() {
UseShortOptionHandling: true,
Commands: []*cli.Command{
{
Name: "find-all-pods",
Args: true,
Name: "total-checkpointable-value",
Args: true,
Usage: "Computes the sum of all shares that would be minted if every EigenPod on the network ran a checkpoint right now.",
Flags: []cli.Flag{
ExecNodeFlag,
BeaconNodeFlag,
Expand Down

0 comments on commit 687154d

Please sign in to comment.