diff --git a/chainio/clients/elcontracts/reader.go b/chainio/clients/elcontracts/reader.go index 1f46ab3d..f33fce91 100644 --- a/chainio/clients/elcontracts/reader.go +++ b/chainio/clients/elcontracts/reader.go @@ -91,67 +91,94 @@ func NewReaderFromConfig( ), nil } +// IsOperatorRegistered returns if an operator is registered func (r *ChainReader) IsOperatorRegistered( ctx context.Context, - operator types.Operator, -) (bool, error) { + request OperatorRequest, +) (OperatorRegisterResponse, error) { if r.delegationManager == nil { - return false, errors.New("DelegationManager contract not provided") + return OperatorRegisterResponse{}, errors.New("DelegationManager contract not provided") + } + + isRegistered, err := r.delegationManager.IsOperator( + &bind.CallOpts{Context: ctx, BlockNumber: request.BlockNumber}, + request.OperatorAddress) + if err != nil { + return OperatorRegisterResponse{}, utils.WrapError("failed to check if operator is registered", err) } - return r.delegationManager.IsOperator(&bind.CallOpts{Context: ctx}, gethcommon.HexToAddress(operator.Address)) + return OperatorRegisterResponse{IsRegistered: isRegistered}, nil } // GetStakerShares returns the amount of shares that a staker has in all of the strategies in which they have nonzero // shares func (r *ChainReader) GetStakerShares( ctx context.Context, - stakerAddress gethcommon.Address, -) ([]gethcommon.Address, []*big.Int, error) { + request StakerRequest, +) (StakerSharesResponse, error) { if r.delegationManager == nil { - return nil, nil, errors.New("DelegationManager contract not provided") + return StakerSharesResponse{}, errors.New("DelegationManager contract not provided") } - return r.delegationManager.GetDepositedShares(&bind.CallOpts{Context: ctx}, stakerAddress) + + strategies, shares, err := r.delegationManager.GetDepositedShares( + &bind.CallOpts{Context: ctx, BlockNumber: request.BlockNumber}, + request.StakerAddress, + ) + if err != nil { + return StakerSharesResponse{}, utils.WrapError("failed to get staker shares", err) + } + + return StakerSharesResponse{StrategiesAddresses: strategies, Shares: shares}, nil } // GetDelegatedOperator returns the operator that a staker has delegated to func (r *ChainReader) GetDelegatedOperator( ctx context.Context, - stakerAddress gethcommon.Address, - blockNumber *big.Int, -) (gethcommon.Address, error) { + request StakerRequest, +) (DelegateOperatorResponse, error) { if r.delegationManager == nil { - return gethcommon.Address{}, errors.New("DelegationManager contract not provided") + return DelegateOperatorResponse{}, errors.New("DelegationManager contract not provided") + } + + operatorAddress, err := r.delegationManager.DelegatedTo( + &bind.CallOpts{Context: ctx, BlockNumber: request.BlockNumber}, + request.StakerAddress, + ) + if err != nil { + return DelegateOperatorResponse{}, utils.WrapError("failed to get delegated operator", err) } - return r.delegationManager.DelegatedTo(&bind.CallOpts{Context: ctx}, stakerAddress) + + return DelegateOperatorResponse{OperatorAddress: operatorAddress}, nil } +// GetOperatorDetails returns the operator's details func (r *ChainReader) GetOperatorDetails( ctx context.Context, - operator types.Operator, -) (types.Operator, error) { + request OperatorRequest, +) (OperatorResponse, error) { if r.delegationManager == nil { - return types.Operator{}, errors.New("DelegationManager contract not provided") + return OperatorResponse{}, errors.New("DelegationManager contract not provided") } delegationManagerAddress, err := r.delegationManager.DelegationApprover( &bind.CallOpts{Context: ctx}, - gethcommon.HexToAddress(operator.Address), + request.OperatorAddress, ) // This call should not fail since it's a getter if err != nil { - return types.Operator{}, err + return OperatorResponse{}, err } isSet, delay, err := r.allocationManager.GetAllocationDelay( &bind.CallOpts{ - Context: ctx, + Context: ctx, + BlockNumber: request.BlockNumber, }, - gethcommon.HexToAddress(operator.Address), + request.OperatorAddress, ) // This call should not fail if err != nil { - return types.Operator{}, err + return OperatorResponse{}, err } var allocationDelay uint32 @@ -161,67 +188,82 @@ func (r *ChainReader) GetOperatorDetails( allocationDelay = 0 } - return types.Operator{ - Address: operator.Address, + operatorDetails := types.Operator{ + Address: request.OperatorAddress.Hex(), DelegationApproverAddress: delegationManagerAddress.Hex(), AllocationDelay: allocationDelay, - }, nil + } + + return OperatorResponse{Operator: operatorDetails}, nil } // GetStrategyAndUnderlyingToken returns the strategy contract and the underlying token address func (r *ChainReader) GetStrategyAndUnderlyingToken( ctx context.Context, - strategyAddr gethcommon.Address, -) (*strategy.ContractIStrategy, gethcommon.Address, error) { - contractStrategy, err := strategy.NewContractIStrategy(strategyAddr, r.ethClient) + request StrategyRequest, +) (StrategyTokenResponse, error) { + contractStrategy, err := strategy.NewContractIStrategy(request.StrategyAddress, r.ethClient) // This call should not fail since it's an init if err != nil { - return nil, gethcommon.Address{}, utils.WrapError("Failed to fetch strategy contract", err) + return StrategyTokenResponse{}, utils.WrapError("Failed to fetch strategy contract", err) } - underlyingTokenAddr, err := contractStrategy.UnderlyingToken(&bind.CallOpts{Context: ctx}) + underlyingTokenAddr, err := contractStrategy.UnderlyingToken( + &bind.CallOpts{Context: ctx, BlockNumber: request.BlockNumber}, + ) if err != nil { - return nil, gethcommon.Address{}, utils.WrapError("Failed to fetch token contract", err) + return StrategyTokenResponse{}, utils.WrapError("Failed to fetch token contract", err) } - return contractStrategy, underlyingTokenAddr, nil + return StrategyTokenResponse{StrategyContract: *contractStrategy, UnderlyingTokenAddress: underlyingTokenAddr}, nil } // GetStrategyAndUnderlyingERC20Token returns the strategy contract, the erc20 bindings for the underlying token // and the underlying token address func (r *ChainReader) GetStrategyAndUnderlyingERC20Token( ctx context.Context, - strategyAddr gethcommon.Address, -) (*strategy.ContractIStrategy, erc20.ContractIERC20Methods, gethcommon.Address, error) { - contractStrategy, err := strategy.NewContractIStrategy(strategyAddr, r.ethClient) + request StrategyRequest, +) (StrategyERC20TokenResponse, error) { + contractStrategy, err := strategy.NewContractIStrategy(request.StrategyAddress, r.ethClient) // This call should not fail since it's an init if err != nil { - return nil, nil, gethcommon.Address{}, utils.WrapError("Failed to fetch strategy contract", err) + return StrategyERC20TokenResponse{}, utils.WrapError("Failed to fetch strategy contract", err) } - underlyingTokenAddr, err := contractStrategy.UnderlyingToken(&bind.CallOpts{Context: ctx}) + underlyingTokenAddr, err := contractStrategy.UnderlyingToken( + &bind.CallOpts{Context: ctx, BlockNumber: request.BlockNumber}, + ) if err != nil { - return nil, nil, gethcommon.Address{}, utils.WrapError("Failed to fetch token contract", err) + return StrategyERC20TokenResponse{}, utils.WrapError("Failed to fetch token contract", err) } contractUnderlyingToken, err := erc20.NewContractIERC20(underlyingTokenAddr, r.ethClient) // This call should not fail, if the strategy does not have an underlying token then it would enter the if above if err != nil { - return nil, nil, gethcommon.Address{}, utils.WrapError("Failed to fetch token contract", err) + return StrategyERC20TokenResponse{}, utils.WrapError("Failed to fetch token contract", err) } - return contractStrategy, contractUnderlyingToken, underlyingTokenAddr, nil + + return StrategyERC20TokenResponse{ + StrategyContract: *contractStrategy, + UnderlyingERC20Contract: contractUnderlyingToken, + UnderlyingTokenAddress: underlyingTokenAddr, + }, nil } func (r *ChainReader) GetOperatorSharesInStrategy( ctx context.Context, - operatorAddr gethcommon.Address, - strategyAddr gethcommon.Address, -) (*big.Int, error) { + request SharesInStrategyRequest, +) (SharesResponse, error) { if r.delegationManager == nil { - return &big.Int{}, errors.New("DelegationManager contract not provided") + return SharesResponse{}, errors.New("DelegationManager contract not provided") } - return r.delegationManager.OperatorShares( - &bind.CallOpts{Context: ctx}, - operatorAddr, - strategyAddr, + shares, err := r.delegationManager.OperatorShares( + &bind.CallOpts{Context: ctx, BlockNumber: request.BlockNumber}, + request.OperatorAddress, + request.StrategyAddress, ) + if err != nil { + return SharesResponse{}, utils.WrapError("failed to get operator shares", err) + } + + return SharesResponse{Shares: shares}, nil } func (r *ChainReader) CalculateDelegationApprovalDigestHash( diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index 9244c698..83a9d002 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -28,34 +28,49 @@ func TestChainReader(t *testing.T) { ctx := context.Background() contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) + operatorAddress := testutils.ANVIL_FIRST_ADDRESS + + // REMOVE THIS WHEN FINISH WITH THE NEW INTERFACE operator := types.Operator{ - Address: testutils.ANVIL_FIRST_ADDRESS, + Address: operatorAddress, + } + + operatorRequest := elcontracts.OperatorRequest{ + OperatorAddress: common.HexToAddress(operatorAddress), + } + + strategyAddr := contractAddrs.Erc20MockStrategy + strategyRequest := elcontracts.StrategyRequest{ + StrategyAddress: strategyAddr, + } + + stakerRequest := elcontracts.StakerRequest{ + StakerAddress: common.HexToAddress(operatorAddress), } t.Run("is operator registered", func(t *testing.T) { - isOperator, err := read_clients.ElChainReader.IsOperatorRegistered(ctx, operator) + response, err := read_clients.ElChainReader.IsOperatorRegistered(ctx, operatorRequest) assert.NoError(t, err) - assert.Equal(t, isOperator, true) + assert.Equal(t, response.IsRegistered, true) }) t.Run("get operator details", func(t *testing.T) { - operatorDetails, err := read_clients.ElChainReader.GetOperatorDetails(ctx, operator) + response, err := read_clients.ElChainReader.GetOperatorDetails(ctx, operatorRequest) assert.NoError(t, err) - assert.NotNil(t, operatorDetails) - assert.Equal(t, operator.Address, operatorDetails.Address) + assert.NotNil(t, response) + assert.Equal(t, operatorRequest.OperatorAddress.Hex(), response.Operator.Address) }) t.Run("get strategy and underlying token", func(t *testing.T) { - strategyAddr := contractAddrs.Erc20MockStrategy - strategy, underlyingTokenAddr, err := read_clients.ElChainReader.GetStrategyAndUnderlyingToken( + response, err := read_clients.ElChainReader.GetStrategyAndUnderlyingToken( ctx, - strategyAddr, + strategyRequest, ) assert.NoError(t, err) - assert.NotNil(t, strategy) - assert.NotEqual(t, common.Address{}, underlyingTokenAddr) + assert.NotNil(t, response) + assert.NotEqual(t, common.Address{}, response.UnderlyingTokenAddress) - erc20Token, err := erc20.NewContractIERC20(underlyingTokenAddr, read_clients.EthHttpClient) + erc20Token, err := erc20.NewContractIERC20(response.UnderlyingTokenAddress, read_clients.EthHttpClient) assert.NoError(t, err) tokenName, err := erc20Token.Name(&bind.CallOpts{}) @@ -64,29 +79,31 @@ func TestChainReader(t *testing.T) { }) t.Run("get strategy and underlying ERC20 token", func(t *testing.T) { - strategyAddr := contractAddrs.Erc20MockStrategy - strategy, contractUnderlyingToken, underlyingTokenAddr, err := read_clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( + erc20Response, err := read_clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( ctx, - strategyAddr, + strategyRequest, ) assert.NoError(t, err) - assert.NotNil(t, strategy) - assert.NotEqual(t, common.Address{}, underlyingTokenAddr) - assert.NotNil(t, contractUnderlyingToken) + assert.NotNil(t, erc20Response) + assert.NotEqual(t, common.Address{}, erc20Response.UnderlyingTokenAddress) + assert.NotNil(t, erc20Response.UnderlyingERC20Contract) - tokenName, err := contractUnderlyingToken.Name(&bind.CallOpts{}) + tokenName, err := erc20Response.UnderlyingERC20Contract.Name(&bind.CallOpts{}) assert.NoError(t, err) assert.NotEmpty(t, tokenName) }) t.Run("get operator shares in strategy", func(t *testing.T) { - shares, err := read_clients.ElChainReader.GetOperatorSharesInStrategy( + shareRequest := elcontracts.SharesInStrategyRequest{ + OperatorAddress: common.HexToAddress(operatorAddress), + StrategyAddress: strategyAddr, + } + sharesResponse, err := read_clients.ElChainReader.GetOperatorSharesInStrategy( ctx, - common.HexToAddress(operator.Address), - contractAddrs.Erc20MockStrategy, + shareRequest, ) assert.NoError(t, err) - assert.NotZero(t, shares) + assert.NotZero(t, sharesResponse.Shares) }) t.Run("calculate delegation approval digest hash", func(t *testing.T) { @@ -122,27 +139,33 @@ func TestChainReader(t *testing.T) { }) t.Run("get staker shares", func(t *testing.T) { - strategies, shares, err := read_clients.ElChainReader.GetStakerShares( + stakerSharesRequest := elcontracts.StakerRequest{ + StakerAddress: common.HexToAddress(operatorAddress), + } + sharesResponse, err := read_clients.ElChainReader.GetStakerShares( ctx, - common.HexToAddress(operator.Address), + stakerSharesRequest, + ) + assert.NotZero(t, len(sharesResponse.StrategiesAddresses), "Strategies has at least one element") + assert.NotZero(t, len(sharesResponse.Shares), "Shares has at least one element") + assert.Equal( + t, + len(sharesResponse.StrategiesAddresses), + len(sharesResponse.Shares), + "Strategies has the same ammount of elements as shares", ) - assert.NotZero(t, len(strategies), "Strategies has at least one element") - assert.NotZero(t, len(shares), "Shares has at least one element") - assert.Equal(t, len(strategies), len(shares), "Strategies has the same ammount of elements as shares") assert.NoError(t, err) }) t.Run("get delegated operator", func(t *testing.T) { - blockNumber := big.NewInt(0) - address, err := read_clients.ElChainReader.GetDelegatedOperator( + operatorResponse, err := read_clients.ElChainReader.GetDelegatedOperator( ctx, - common.HexToAddress(operator.Address), - blockNumber, + stakerRequest, ) assert.NoError(t, err) // The delegated operator of an operator is the operator itself - assert.Equal(t, address.String(), operator.Address) + assert.Equal(t, operatorResponse.OperatorAddress.String(), operator.Address) }) t.Run("GetOperatorShares", func(t *testing.T) { @@ -408,6 +431,10 @@ func TestGetCumulativeClaimedRewards(t *testing.T) { } privateKeyHex := testutils.ANVIL_FIRST_PRIVATE_KEY + strategyRequest := elcontracts.StrategyRequest{ + StrategyAddress: contractAddrs.Erc20MockStrategy, + } + // Create ChainWriter chainWriter, err := testclients.NewTestChainWriterFromConfig(anvilHttpEndpoint, privateKeyHex, config) require.NoError(t, err) @@ -421,20 +448,19 @@ func TestGetCumulativeClaimedRewards(t *testing.T) { require.NoError(t, err) require.True(t, receipt.Status == gethtypes.ReceiptStatusSuccessful) - strategyAddr := contractAddrs.Erc20MockStrategy - strategy, contractUnderlyingToken, underlyingTokenAddr, err := clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( + response, err := clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( ctx, - strategyAddr, + strategyRequest, ) assert.NoError(t, err) - assert.NotNil(t, strategy) - assert.NotEqual(t, common.Address{}, underlyingTokenAddr) - assert.NotNil(t, contractUnderlyingToken) + assert.NotNil(t, response.StrategyContract) + assert.NotEqual(t, common.Address{}, response.UnderlyingTokenAddress) + assert.NotNil(t, response.UnderlyingERC20Contract) anvil_address := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS) // This tests that without claims result is zero - claimed, err := chainReader.GetCumulativeClaimed(ctx, anvil_address, underlyingTokenAddr) + claimed, err := chainReader.GetCumulativeClaimed(ctx, anvil_address, response.UnderlyingTokenAddress) assert.Zero(t, claimed.Cmp(big.NewInt(0))) assert.NoError(t, err) @@ -447,7 +473,7 @@ func TestGetCumulativeClaimedRewards(t *testing.T) { require.True(t, receipt.Status == gethtypes.ReceiptStatusSuccessful) // This tests that with a claim result is cumulativeEarnings - claimed, err = chainReader.GetCumulativeClaimed(ctx, anvil_address, underlyingTokenAddr) + claimed, err = chainReader.GetCumulativeClaimed(ctx, anvil_address, response.UnderlyingTokenAddress) assert.Equal(t, claimed, big.NewInt(cumulativeEarnings)) assert.NoError(t, err) } @@ -465,6 +491,10 @@ func TestCheckClaim(t *testing.T) { } privateKeyHex := testutils.ANVIL_FIRST_PRIVATE_KEY + strategyRequest := elcontracts.StrategyRequest{ + StrategyAddress: contractAddrs.Erc20MockStrategy, + } + // Create ChainWriter and chain reader chainWriter, err := testclients.NewTestChainWriterFromConfig(anvilHttpEndpoint, privateKeyHex, config) require.NoError(t, err) @@ -486,15 +516,14 @@ func TestCheckClaim(t *testing.T) { require.NoError(t, err) require.True(t, receipt.Status == gethtypes.ReceiptStatusSuccessful) - strategyAddr := contractAddrs.Erc20MockStrategy - strategy, contractUnderlyingToken, underlyingTokenAddr, err := clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( + response, err := clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( ctx, - strategyAddr, + strategyRequest, ) assert.NoError(t, err) - assert.NotNil(t, strategy) - assert.NotEqual(t, common.Address{}, underlyingTokenAddr) - assert.NotNil(t, contractUnderlyingToken) + assert.NotNil(t, response.StrategyContract) + assert.NotEqual(t, common.Address{}, response.UnderlyingTokenAddress) + assert.NotNil(t, response.UnderlyingERC20Contract) checked, err := chainReader.CheckClaim(ctx, *claim) require.NoError(t, err) @@ -582,15 +611,15 @@ func TestGetAllocatableMagnitudeAndGetMaxMagnitudes(t *testing.T) { assert.Equal(t, maxMagnitudes[0], allocable+allocatable_reduction) // Check that the new allocationDelay is equal to delay - op := types.Operator{ - Address: operatorAddr.String(), + operatorRequest := elcontracts.OperatorRequest{ + OperatorAddress: operatorAddr, } - operatorDetails, err := chainReader.GetOperatorDetails(ctx, op) + response, err := chainReader.GetOperatorDetails(ctx, operatorRequest) assert.NoError(t, err) - assert.NotNil(t, operatorDetails) - assert.Equal(t, op.Address, operatorDetails.Address) - assert.Equal(t, delay, operatorDetails.AllocationDelay) + assert.NotNil(t, response.Operator) + assert.Equal(t, operatorRequest.OperatorAddress.Hex(), response.Operator.Address) + assert.Equal(t, delay, response.Operator.AllocationDelay) } func TestAdminFunctions(t *testing.T) { @@ -767,15 +796,16 @@ func TestContractErrorCases(t *testing.T) { // This address does not belong to a Token contract strategyAddr := common.HexToAddress("34634374736473673643") + strategyRequest := elcontracts.StrategyRequest{StrategyAddress: strategyAddr} t.Run("GetStrategyAndUnderlyingToken", func(t *testing.T) { - _, _, err := chainReader.GetStrategyAndUnderlyingToken(ctx, strategyAddr) + _, err := chainReader.GetStrategyAndUnderlyingToken(ctx, strategyRequest) assert.Error(t, err) assert.Equal(t, err.Error(), "Failed to fetch token contract: no contract code at given address") }) t.Run("GetStrategyAndUnderlyingERC20Token", func(t *testing.T) { - _, _, _, err := chainReader.GetStrategyAndUnderlyingERC20Token(ctx, strategyAddr) + _, err := chainReader.GetStrategyAndUnderlyingERC20Token(ctx, strategyRequest) assert.Error(t, err) assert.Equal(t, err.Error(), "Failed to fetch token contract: no contract code at given address") }) @@ -795,6 +825,7 @@ func TestInvalidConfig(t *testing.T) { operator := types.Operator{ Address: operatorAddr, } + operatorRequest := elcontracts.OperatorRequest{OperatorAddress: common.HexToAddress(operatorAddr)} config := elcontracts.Config{} chainReader, err := testclients.NewTestChainReaderFromConfig(anvilHttpEndpoint, config) @@ -802,13 +833,13 @@ func TestInvalidConfig(t *testing.T) { t.Run("try to check if operator is registered with invalid config", func(t *testing.T) { // IsOperatorRegistered needs a correct DelegationManagerAddress - _, err := chainReader.IsOperatorRegistered(context.Background(), operator) + _, err := chainReader.IsOperatorRegistered(context.Background(), operatorRequest) require.Error(t, err) }) t.Run("get operator details with invalid config", func(t *testing.T) { // GetOperatorDetails needs a correct DelegationManagerAddress - _, err := chainReader.GetOperatorDetails(context.Background(), operator) + _, err := chainReader.GetOperatorDetails(context.Background(), operatorRequest) require.Error(t, err) }) @@ -827,17 +858,23 @@ func TestInvalidConfig(t *testing.T) { t.Run("try to get strategy and underlying token with wrong strategy address", func(t *testing.T) { // Invalid strategy address strategyAddr := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS) + strategyRequest := elcontracts.StrategyRequest{StrategyAddress: strategyAddr} + operatorAddr := common.HexToAddress(testutils.ANVIL_SECOND_ADDRESS) + sharesStrategyRequest := elcontracts.SharesInStrategyRequest{ + OperatorAddress: operatorAddr, + StrategyAddress: strategyAddr, + } // GetOperatorSharesInStrategy needs a correct DelegationManagerAddress - _, err := chainReader.GetOperatorSharesInStrategy(context.Background(), operatorAddr, strategyAddr) + _, err := chainReader.GetOperatorSharesInStrategy(context.Background(), sharesStrategyRequest) require.Error(t, err) // GetStrategyAndUnderlyingToken needs a correct StrategyAddress - _, _, err = chainReader.GetStrategyAndUnderlyingToken(context.Background(), strategyAddr) + _, err = chainReader.GetStrategyAndUnderlyingToken(context.Background(), strategyRequest) require.Error(t, err) - _, _, _, err = chainReader.GetStrategyAndUnderlyingERC20Token(context.Background(), strategyAddr) + _, err = chainReader.GetStrategyAndUnderlyingERC20Token(context.Background(), strategyRequest) require.Error(t, err) }) @@ -925,16 +962,21 @@ func TestInvalidConfig(t *testing.T) { t.Run("try to get a staker shares with invalid config", func(t *testing.T) { // GetStakerShares needs a correct DelegationManagerAddress - _, _, err := chainReader.GetStakerShares(context.Background(), common.HexToAddress(operator.Address)) + stakerRequest := elcontracts.StakerRequest{ + StakerAddress: common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS), + } + _, err := chainReader.GetStakerShares(context.Background(), stakerRequest) require.Error(t, err) }) t.Run("try to get the delegated operator shares with invalid config", func(t *testing.T) { // GetDelegatedOperator needs a correct DelegationManagerAddress + stakerRequest := elcontracts.StakerRequest{ + StakerAddress: common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS), + } _, err := chainReader.GetDelegatedOperator( context.Background(), - common.HexToAddress(operator.Address), - big.NewInt(0), + stakerRequest, ) require.Error(t, err) }) diff --git a/chainio/clients/elcontracts/types.go b/chainio/clients/elcontracts/types.go index 21dd8ea4..ed6ddaa7 100644 --- a/chainio/clients/elcontracts/types.go +++ b/chainio/clients/elcontracts/types.go @@ -4,7 +4,10 @@ import ( "math/big" allocationmanager "github.com/Layr-Labs/eigensdk-go/contracts/bindings/AllocationManager" + erc20 "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IERC20" + strategy "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IStrategy" "github.com/Layr-Labs/eigensdk-go/crypto/bls" + "github.com/Layr-Labs/eigensdk-go/types" "github.com/ethereum/go-ethereum/common" ) @@ -81,3 +84,74 @@ type RemovePendingAdminRequest struct { AdminAddress common.Address WaitForReceipt bool } + +// READER TYPES + +// OperatorRequest represents a request that requires an operator's address +// If `BlockNumber` is nil, the latest block will be used +type OperatorRequest struct { + BlockNumber *big.Int + OperatorAddress common.Address +} + +// OperatorResponse represents the operator information +type OperatorResponse struct { + Operator types.Operator +} + +// StrategyRequest represents a request that requires a strategy's address +// If `BlockNumber` is nil, the latest block will be used +type StrategyRequest struct { + BlockNumber *big.Int + StrategyAddress common.Address +} + +// StrategyTokenResponse contains the strategy contract and the underlying token address +type StrategyTokenResponse struct { + StrategyContract strategy.ContractIStrategy + UnderlyingTokenAddress common.Address +} + +// StrategyERC20TokenResponse contains the strategy contract, the underlying token address and the underlying ERC20 +// contract +type StrategyERC20TokenResponse struct { + StrategyContract strategy.ContractIStrategy + UnderlyingERC20Contract erc20.ContractIERC20Methods + UnderlyingTokenAddress common.Address +} + +// OperatorRegisterResponse indicates if the operator is registered or not +type OperatorRegisterResponse struct { + IsRegistered bool +} + +// StakerRequest represents a request that requires a staker's address +// If `BlockNumber` is nil, the latest block will be used +type StakerRequest struct { + BlockNumber *big.Int + StakerAddress common.Address +} + +// StakerSharesResponse contains the staker's shares +type StakerSharesResponse struct { + StrategiesAddresses []common.Address + Shares []*big.Int +} + +// DelegateOperatorResponse represents the operator's delegate address +type DelegateOperatorResponse struct { + OperatorAddress common.Address +} + +// SharesInStrategyRequest represents a request that requires both strategy's address and operator's address +// If `BlockNumber` is nil, the latest block will be used +type SharesInStrategyRequest struct { + BlockNumber *big.Int + OperatorAddress common.Address + StrategyAddress common.Address +} + +// ShareResponse contains the numbers of shares +type SharesResponse struct { + Shares *big.Int +} diff --git a/chainio/clients/elcontracts/writer.go b/chainio/clients/elcontracts/writer.go index fc95ee6c..466a6a1d 100644 --- a/chainio/clients/elcontracts/writer.go +++ b/chainio/clients/elcontracts/writer.go @@ -18,9 +18,7 @@ import ( avsdirectory "github.com/Layr-Labs/eigensdk-go/contracts/bindings/AVSDirectory" allocationmanager "github.com/Layr-Labs/eigensdk-go/contracts/bindings/AllocationManager" delegationmanager "github.com/Layr-Labs/eigensdk-go/contracts/bindings/DelegationManager" - 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" permissioncontroller "github.com/Layr-Labs/eigensdk-go/contracts/bindings/PermissionController" regcoord "github.com/Layr-Labs/eigensdk-go/contracts/bindings/RegistryCoordinator" strategymanager "github.com/Layr-Labs/eigensdk-go/contracts/bindings/StrategyManager" @@ -33,8 +31,8 @@ import ( type Reader interface { GetStrategyAndUnderlyingERC20Token( - ctx context.Context, strategyAddr gethcommon.Address, - ) (*strategy.ContractIStrategy, erc20.ContractIERC20Methods, gethcommon.Address, error) + ctx context.Context, request StrategyRequest, + ) (StrategyERC20TokenResponse, error) } type ChainWriter struct { @@ -242,15 +240,15 @@ func (w *ChainWriter) DepositERC20IntoStrategy( if err != nil { return nil, err } - _, underlyingTokenContract, underlyingTokenAddr, err := w.elChainReader.GetStrategyAndUnderlyingERC20Token( + response, err := w.elChainReader.GetStrategyAndUnderlyingERC20Token( ctx, - strategyAddr, + StrategyRequest{StrategyAddress: strategyAddr}, ) if err != nil { return nil, err } - tx, err := underlyingTokenContract.Approve(noSendTxOpts, w.strategyManagerAddr, amount) + tx, err := response.UnderlyingERC20Contract.Approve(noSendTxOpts, w.strategyManagerAddr, amount) if err != nil { return nil, errors.Join(errors.New("failed to approve token transfer"), err) } @@ -259,7 +257,7 @@ func (w *ChainWriter) DepositERC20IntoStrategy( return nil, errors.New("failed to send tx with err: " + err.Error()) } - tx, err = w.strategyManager.DepositIntoStrategy(noSendTxOpts, strategyAddr, underlyingTokenAddr, amount) + tx, err = w.strategyManager.DepositIntoStrategy(noSendTxOpts, strategyAddr, response.UnderlyingTokenAddress, amount) if err != nil { return nil, err }