Skip to content

Commit

Permalink
chore: clean up and tests 1 of n (#203)
Browse files Browse the repository at this point in the history
* chore: clean up and tests

* add tests and fakes
  • Loading branch information
shrimalmadhur authored Aug 27, 2024
1 parent 93010df commit d6ca32a
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 46 deletions.
29 changes: 9 additions & 20 deletions pkg/rewards/claim.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/Layr-Labs/eigenlayer-cli/pkg/internal/common"
"github.com/Layr-Labs/eigenlayer-cli/pkg/internal/common/flags"
"github.com/Layr-Labs/eigenlayer-cli/pkg/telemetry"
"github.com/Layr-Labs/eigenlayer-cli/pkg/types"
"github.com/Layr-Labs/eigenlayer-cli/pkg/utils"

contractrewardscoordinator "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IRewardsCoordinator"
Expand All @@ -36,22 +35,13 @@ import (
"github.com/urfave/cli/v2"
)

type ClaimConfig struct {
Network string
RPCUrl string
EarnerAddress gethcommon.Address
RecipientAddress gethcommon.Address
ClaimerAddress gethcommon.Address
Output string
OutputType string
Broadcast bool
TokenAddresses []gethcommon.Address
RewardsCoordinatorAddress gethcommon.Address
ClaimTimestamp string
ChainID *big.Int
ProofStoreBaseURL string
Environment string
SignerConfig *types.SignerConfig
type elChainReader interface {
GetDistributionRootsLength(opts *bind.CallOpts) (*big.Int, error)
GetRootIndexFromHash(opts *bind.CallOpts, hash [32]byte) (uint32, error)
GetCurrentClaimableDistributionRoot(
opts *bind.CallOpts,
) (rewardscoordinator.IRewardsCoordinatorDistributionRoot, error)
CurrRewardsCalculationEndTimestamp(opts *bind.CallOpts) (uint32, error)
}

func ClaimCmd(p utils.Prompter) *cli.Command {
Expand Down Expand Up @@ -123,7 +113,7 @@ func Claim(cCtx *cli.Context, p utils.Prompter) error {
http.DefaultClient,
)

claimDate, rootIndex, err := getClaimDistributionRoot(ctx, config.ClaimTimestamp, df, elReader, logger)
claimDate, rootIndex, err := getClaimDistributionRoot(ctx, config.ClaimTimestamp, elReader, logger)
if err != nil {
return eigenSdkUtils.WrapError("failed to get claim distribution root", err)
}
Expand Down Expand Up @@ -275,8 +265,7 @@ func Claim(cCtx *cli.Context, p utils.Prompter) error {
func getClaimDistributionRoot(
ctx context.Context,
claimTimestamp string,
df *httpProofDataFetcher.HttpProofDataFetcher,
elReader *elcontracts.ChainReader,
elReader elChainReader,
logger logging.Logger,
) (string, uint32, error) {
if claimTimestamp == "latest" {
Expand Down
170 changes: 170 additions & 0 deletions pkg/rewards/claim_test.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,101 @@
package rewards

import (
"context"
"errors"
"flag"
"math/big"
"os"
"sort"
"testing"
"time"

"github.com/Layr-Labs/eigenlayer-cli/pkg/internal/common/flags"
"github.com/Layr-Labs/eigenlayer-cli/pkg/internal/testutils"

rewardscoordinator "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IRewardsCoordinator"
"github.com/Layr-Labs/eigensdk-go/logging"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"

"github.com/stretchr/testify/assert"
"github.com/urfave/cli/v2"
)

type fakeELReader struct {
roots []rewardscoordinator.IRewardsCoordinatorDistributionRoot
}

func newFakeELReader(now time.Time) *fakeELReader {
roots := make([]rewardscoordinator.IRewardsCoordinatorDistributionRoot, 0)
rootOne := rewardscoordinator.IRewardsCoordinatorDistributionRoot{
Root: [32]byte{0x01},
RewardsCalculationEndTimestamp: uint32(now.Add(-time.Hour).Unix()),
ActivatedAt: uint32(now.Add(time.Hour).Unix()),
Disabled: false,
}

// This is the current claimable distribution root
rootTwo := rewardscoordinator.IRewardsCoordinatorDistributionRoot{
Root: [32]byte{0x02},
RewardsCalculationEndTimestamp: uint32(now.Add(48 * -time.Hour).Unix()),
ActivatedAt: uint32(now.Add(-24 * time.Hour).Unix()),
Disabled: false,
}

rootThree := rewardscoordinator.IRewardsCoordinatorDistributionRoot{
Root: [32]byte{0x03},
RewardsCalculationEndTimestamp: uint32(now.Add(32 * -time.Hour).Unix()),
ActivatedAt: uint32(now.Add(-12 * time.Minute).Unix()),
Disabled: true,
}

roots = append(roots, rootOne, rootTwo, rootThree)
// ascending sort order
sort.Slice(roots, func(i, j int) bool {
return roots[i].ActivatedAt < roots[j].ActivatedAt
})
return &fakeELReader{
roots: roots,
}
}

func (f *fakeELReader) GetDistributionRootsLength(opts *bind.CallOpts) (*big.Int, error) {
return big.NewInt(int64(len(f.roots))), nil
}

func (f *fakeELReader) GetRootIndexFromHash(opts *bind.CallOpts, hash [32]byte) (uint32, error) {
for i, root := range f.roots {
if root.Root == hash {
return uint32(i), nil
}
}
return 0, nil
}

func (f *fakeELReader) GetCurrentClaimableDistributionRoot(
opts *bind.CallOpts,
) (rewardscoordinator.IRewardsCoordinatorDistributionRoot, error) {
// iterate from end to start since we want the latest active root
// and the roots are sorted in ascending order of activation time
for i := len(f.roots) - 1; i >= 0; i-- {
if !f.roots[i].Disabled && f.roots[i].ActivatedAt < uint32(time.Now().Unix()) {
return f.roots[i], nil
}
}

return rewardscoordinator.IRewardsCoordinatorDistributionRoot{}, errors.New("no active distribution root found")
}

func (f *fakeELReader) CurrRewardsCalculationEndTimestamp(opts *bind.CallOpts) (uint32, error) {
rootLen, err := f.GetDistributionRootsLength(opts)
if err != nil {
return 0, err
}
return f.roots[rootLen.Uint64()-1].RewardsCalculationEndTimestamp, nil
}

func TestReadAndValidateConfig_NoRecipientProvided(t *testing.T) {
earnerAddress := testutils.GenerateRandomEthereumAddressString()
fs := flag.NewFlagSet("test", flag.ContinueOnError)
Expand Down Expand Up @@ -52,3 +133,92 @@ func TestReadAndValidateConfig_RecipientProvided(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, common.HexToAddress(recipientAddress), config.RecipientAddress)
}

func TestReadAndValidateConfig_NoClaimerProvided(t *testing.T) {
earnerAddress := testutils.GenerateRandomEthereumAddressString()
fs := flag.NewFlagSet("test", flag.ContinueOnError)
fs.String(flags.ETHRpcUrlFlag.Name, "rpc", "")
fs.String(EarnerAddressFlag.Name, earnerAddress, "")
fs.String(RewardsCoordinatorAddressFlag.Name, "0x1234", "")
fs.String(ClaimTimestampFlag.Name, "latest", "")
fs.String(ProofStoreBaseURLFlag.Name, "dummy-url", "")
cliCtx := cli.NewContext(nil, fs, nil)

logger := logging.NewJsonSLogger(os.Stdout, &logging.SLoggerOptions{})

config, err := readAndValidateClaimConfig(cliCtx, logger)

assert.NoError(t, err)
assert.Equal(t, common.HexToAddress(earnerAddress), config.ClaimerAddress)
}

func TestReadAndValidateConfig_ClaimerProvided(t *testing.T) {
claimerAddress := testutils.GenerateRandomEthereumAddressString()
fs := flag.NewFlagSet("test", flag.ContinueOnError)
fs.String(flags.ETHRpcUrlFlag.Name, "rpc", "")
fs.String(ClaimerAddressFlag.Name, claimerAddress, "")
fs.String(RewardsCoordinatorAddressFlag.Name, "0x1234", "")
fs.String(ClaimTimestampFlag.Name, "latest", "")
fs.String(ProofStoreBaseURLFlag.Name, "dummy-url", "")
cliCtx := cli.NewContext(nil, fs, nil)

logger := logging.NewJsonSLogger(os.Stdout, &logging.SLoggerOptions{})

config, err := readAndValidateClaimConfig(cliCtx, logger)

assert.NoError(t, err)
assert.Equal(t, common.HexToAddress(claimerAddress), config.ClaimerAddress)
}

func TestGetClaimDistributionRoot(t *testing.T) {
now := time.Now()

tests := []struct {
name string
claimTimestamp string
expectErr bool
expectedClaimDate string
expectedRootIndex uint32
}{
{
name: "latest root",
claimTimestamp: "latest",
expectErr: false,
expectedClaimDate: now.Add(-time.Hour).UTC().Format(time.DateOnly),
expectedRootIndex: 2,
},
{
name: "latest active root",
claimTimestamp: "latest_active",
expectErr: false,
expectedClaimDate: now.Add(-48 * time.Hour).UTC().Format(time.DateOnly),
expectedRootIndex: 0,
},
{
name: "none of them",
claimTimestamp: "none",
expectErr: true,
},
}

reader := newFakeELReader(now)
logger := logging.NewJsonSLogger(os.Stdout, &logging.SLoggerOptions{})

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
claimDate, rootIndex, err := getClaimDistributionRoot(
context.Background(),
tt.claimTimestamp,
reader,
logger,
)
if tt.expectErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.expectedClaimDate, claimDate)
assert.Equal(t, tt.expectedRootIndex, rootIndex)
})
}
}
15 changes: 0 additions & 15 deletions pkg/rewards/setclaimer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ package rewards
import (
"context"
"fmt"
"math/big"
"sort"

"github.com/Layr-Labs/eigenlayer-cli/pkg/internal/common"
"github.com/Layr-Labs/eigenlayer-cli/pkg/internal/common/flags"
"github.com/Layr-Labs/eigenlayer-cli/pkg/telemetry"
"github.com/Layr-Labs/eigenlayer-cli/pkg/types"
"github.com/Layr-Labs/eigenlayer-cli/pkg/utils"

"github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts"
Expand All @@ -23,19 +21,6 @@ import (
"github.com/urfave/cli/v2"
)

type SetClaimerConfig struct {
ClaimerAddress gethcommon.Address
Network string
RPCUrl string
Broadcast bool
RewardsCoordinatorAddress gethcommon.Address
ChainID *big.Int
SignerConfig *types.SignerConfig
EarnerAddress gethcommon.Address
Output string
OutputType string
}

func SetClaimerCmd(p utils.Prompter) *cli.Command {
setClaimerCmd := &cli.Command{
Name: "set-claimer",
Expand Down
10 changes: 0 additions & 10 deletions pkg/rewards/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,6 @@ const (
GetEarnedTokensForStrategyEndpoint = "grpc/eigenlayer.RewardsService/GetEarnedTokensForStrategy"
)

type ShowConfig struct {
EarnerAddress gethcommon.Address
NumberOfDays int64
Network string
Environment string
ClaimType ClaimType
ChainID *big.Int
Output string
}

func ShowCmd(p utils.Prompter) *cli.Command {
showCmd := &cli.Command{
Name: "show",
Expand Down
48 changes: 47 additions & 1 deletion pkg/rewards/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package rewards

import "math/big"
import (
"math/big"

"github.com/Layr-Labs/eigenlayer-cli/pkg/types"
gethcommon "github.com/ethereum/go-ethereum/common"
)

type RewardResponse struct {
Rewards []Reward `json:"rewards"`
Expand Down Expand Up @@ -37,3 +42,44 @@ type NormalizedUnclaimedReward struct {
TokenAddress string `csv:"tokenAddress"`
WeiAmount *big.Int `csv:"weiAmount"`
}

type ClaimConfig struct {
Network string
RPCUrl string
EarnerAddress gethcommon.Address
RecipientAddress gethcommon.Address
ClaimerAddress gethcommon.Address
Output string
OutputType string
Broadcast bool
TokenAddresses []gethcommon.Address
RewardsCoordinatorAddress gethcommon.Address
ClaimTimestamp string
ChainID *big.Int
ProofStoreBaseURL string
Environment string
SignerConfig *types.SignerConfig
}

type SetClaimerConfig struct {
ClaimerAddress gethcommon.Address
Network string
RPCUrl string
Broadcast bool
RewardsCoordinatorAddress gethcommon.Address
ChainID *big.Int
SignerConfig *types.SignerConfig
EarnerAddress gethcommon.Address
Output string
OutputType string
}

type ShowConfig struct {
EarnerAddress gethcommon.Address
NumberOfDays int64
Network string
Environment string
ClaimType ClaimType
ChainID *big.Int
Output string
}

0 comments on commit d6ca32a

Please sign in to comment.