Skip to content

Commit

Permalink
add test for ProcessClaim method. To do: mint tokens to rewardsCoordi…
Browse files Browse the repository at this point in the history
…nator
  • Loading branch information
ricomateo committed Jan 9, 2025
1 parent 397e9a2 commit ba2f314
Showing 1 changed file with 176 additions and 0 deletions.
176 changes: 176 additions & 0 deletions chainio/clients/elcontracts/writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package elcontracts_test

import (
"context"
"encoding/hex"
"fmt"
"math/big"
"os"
"testing"
Expand All @@ -16,10 +18,13 @@ import (
"github.com/Layr-Labs/eigensdk-go/signerv2"
"github.com/Layr-Labs/eigensdk-go/types"

erc20 "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IERC20"
rewardscoordinator "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IRewardsCoordinator"
strategy "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IStrategy"
"github.com/Layr-Labs/eigensdk-go/testutils"
"github.com/Layr-Labs/eigensdk-go/testutils/testclients"
"github.com/Layr-Labs/eigensdk-go/utils"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
gethtypes "github.com/ethereum/go-ethereum/core/types"

Expand Down Expand Up @@ -863,6 +868,177 @@ func TestRemoveAdmin(t *testing.T) {
})
}

func TestProcessClaim(t *testing.T) {
testConfig := testutils.GetDefaultTestConfig()
anvilC, err := testutils.StartAnvilContainer(testConfig.AnvilStateFileName)
require.NoError(t, err)
anvilHttpEndpoint, err := anvilC.Endpoint(context.Background(), "http")
require.NoError(t, err)

privateKeyHex := "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint)

rewardsCoordinatorAddr := contractAddrs.RewardsCoordinator
config := elcontracts.Config{
DelegationManagerAddress: contractAddrs.DelegationManager,
RewardsCoordinatorAddress: rewardsCoordinatorAddr,
}

// Create ChainWriter
chainWriter, err := newTestChainWriterFromConfig(anvilHttpEndpoint, privateKeyHex, config)
require.NoError(t, err)

chainReader, err := newTestChainReaderFromConfig(anvilHttpEndpoint, config)
require.NoError(t, err)

activationDelay := uint32(0)
// Set activation delay to zero so that the earnings can be claimed right after submitting the root
receipt, err := setTestRewardsCoordinatorActivationDelay(anvilHttpEndpoint, privateKeyHex, activationDelay)
require.NoError(t, err)
require.True(t, receipt.Status == SUCCESS_STATUS)

waitForReceipt := true
cumulativeEarnings := int64(42)
earner := common.HexToAddress("0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6")
_, claim, err := newTestClaim(chainReader, anvilHttpEndpoint, cumulativeEarnings, privateKeyHex)
require.NoError(t, err)

receipt, err = chainWriter.ProcessClaim(context.Background(), *claim, earner, waitForReceipt)
require.NoError(t, err)
require.True(t, receipt.Status == SUCCESS_STATUS)
}

func newTestClaim(chainReader *elcontracts.ChainReader, httpEndpoint string, cumulativeEarnings int64, privateKeyHex string) ([32]byte, *rewardscoordinator.IRewardsCoordinatorTypesRewardsMerkleClaim, error) {
contractAddrs := testutils.GetContractAddressesFromContractRegistry(httpEndpoint)
mockStrategyAddr := contractAddrs.Erc20MockStrategy
rewardsCoordinatorAddr := contractAddrs.RewardsCoordinator
ethClient, err := ethclient.Dial(httpEndpoint)
emptyRoot := [32]byte{}
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to create eth client", err)
}
contractStrategy, err := strategy.NewContractIStrategy(mockStrategyAddr, ethClient)
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to fetch strategy contract", err)
}
tokenAddr, err := contractStrategy.UnderlyingToken(&bind.CallOpts{Context: context.Background()})
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to fetch token address", err)
}

_, err = erc20.NewContractIERC20(tokenAddr, ethClient) // token
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to create token contract", err)
}
// TODO: token.mint

// Generate token tree leaf
// For the tree structure, see https://github.com/Layr-Labs/eigenlayer-contracts/blob/a888a1cd1479438dda4b138245a69177b125a973/docs/core/RewardsCoordinator.md#rewards-merkle-tree-structure
earnerAddr := common.HexToAddress("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266")
tokenLeaf := rewardscoordinator.IRewardsCoordinatorTypesTokenTreeMerkleLeaf{
Token: tokenAddr,
CumulativeEarnings: big.NewInt(cumulativeEarnings),
}
// Hash token tree leaf to get root
encodedTokenLeaf := []byte{}
tokenLeafSalt := uint8(1)

// Write the *big.Int to a 32-byte sized buffer to match the uint256 length
cumulativeEarningsBytes := [32]byte{}
tokenLeaf.CumulativeEarnings.FillBytes(cumulativeEarningsBytes[:])

encodedTokenLeaf = append(encodedTokenLeaf, tokenLeafSalt)
encodedTokenLeaf = append(encodedTokenLeaf, tokenLeaf.Token.Bytes()...)
encodedTokenLeaf = append(encodedTokenLeaf, cumulativeEarningsBytes[:]...)

hexEncodedTokenLeaf := hex.EncodeToString(encodedTokenLeaf)
fmt.Println("hexEncodedTokenLeaf = ", hexEncodedTokenLeaf)

// Hash token tree leaf to get root
earnerTokenRoot := crypto.Keccak256(encodedTokenLeaf)

// Generate earner tree leaf
earnerLeaf := rewardscoordinator.IRewardsCoordinatorTypesEarnerTreeMerkleLeaf{
Earner: earnerAddr,
EarnerTokenRoot: [32]byte(earnerTokenRoot),
}
encodedEarnerLeaf := []byte{}
earnerLeafSalt := uint8(0)
encodedEarnerLeaf = append(encodedEarnerLeaf, earnerLeafSalt)
encodedEarnerLeaf = append(encodedEarnerLeaf, earnerLeaf.Earner.Bytes()...)
encodedEarnerLeaf = append(encodedEarnerLeaf, earnerTokenRoot...)

hexEncodedEarnerLeaf := hex.EncodeToString(encodedEarnerLeaf)
fmt.Println("hexEncodedEarnerLeaf = ", hexEncodedEarnerLeaf)
// Hash earner tree leaf to get root
earnerTreeRoot := crypto.Keccak256(encodedEarnerLeaf)

// Fetch the next root index from contract
nextRootIndex, err := chainReader.GetDistributionRootsLength(context.Background())
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to call GetDistributionRootsLength", err)
}
tokenLeaves := []rewardscoordinator.IRewardsCoordinatorTypesTokenTreeMerkleLeaf{tokenLeaf}
// Construct the claim
claim := rewardscoordinator.IRewardsCoordinatorTypesRewardsMerkleClaim{
RootIndex: uint32(nextRootIndex.Uint64()),
EarnerIndex: 0,
// Empty proof because leaf == root
EarnerTreeProof: []byte{},
EarnerLeaf: earnerLeaf,
TokenIndices: []uint32{0},
// Empty proof because leaf == root
TokenTreeProofs: [][]byte{{}},
TokenLeaves: tokenLeaves,
}

root := earnerTreeRoot
// Fetch the current timestamp to increase it
currRewardsCalculationEndTimestamp, err := chainReader.CurrRewardsCalculationEndTimestamp(context.Background())
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to call CurrRewardsCalculationEndTimestamp", err)
}

rewardsCoordinator, err := rewardscoordinator.NewContractIRewardsCoordinator(rewardsCoordinatorAddr, ethClient)
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to create rewards coordinator contract", err)
}

txManager, err := newTestTxManager(httpEndpoint, privateKeyHex)
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to create tx manager", err)
}

noSendOpts, err := txManager.GetNoSendTxOpts()
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to get NoSend tx opts", err)
}

rewardsUpdater := common.HexToAddress("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266")
tx, err := rewardsCoordinator.SetRewardsUpdater(noSendOpts, rewardsUpdater)
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to create SetRewardsUpdater tx", err)
}

waitForReceipt := true
_, err = txManager.Send(context.Background(), tx, waitForReceipt)
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to setRewardsUpdate", err)
}

tx, err = rewardsCoordinator.SubmitRoot(noSendOpts, [32]byte(root), currRewardsCalculationEndTimestamp+1)
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to create SubmitRoot tx", err)
}

_, err = txManager.Send(context.Background(), tx, waitForReceipt)
if err != nil {
return emptyRoot, nil, utils.WrapError("Failed to submit root", err)
}

return [32]byte(root), &claim, nil
}

func createOperatorSet(
client *clients.Clients,
avsAddress common.Address,
Expand Down

0 comments on commit ba2f314

Please sign in to comment.