From 65792b2cbd3eadb1677867efcd45911539d169eb Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Tue, 14 Jan 2025 11:25:36 -0300 Subject: [PATCH 01/21] Add test covering GetAllocatableMagnitude and GetMaxMagnitudes --- chainio/clients/elcontracts/reader_test.go | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index e12e3a0f..7ff6d87c 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -152,6 +152,29 @@ func TestChainReader(t *testing.T) { assert.Equal(t, address.String(), operator.Address) }) + t.Run("get Allocatable Magnitude", func(t *testing.T) { + // Without changes, Allocable magnitude is max magnitude + + rewardsCoordinatorAddr := contractAddrs.RewardsCoordinator + config := elcontracts.Config{ + DelegationManagerAddress: contractAddrs.DelegationManager, + RewardsCoordinatorAddress: rewardsCoordinatorAddr, + } + + chainReader, err := NewTestChainReaderFromConfig(anvilHttpEndpoint, config) + require.NoError(t, err) + + strategyAddr := contractAddrs.Erc20MockStrategy + + strategies := []common.Address{strategyAddr} + maxmagnitude, err := chainReader.GetMaxMagnitudes(ctx, common.HexToAddress(ANVIL_FIRST_ADDRESS), strategies) + assert.NoError(t, err) + + allocable, err := chainReader.GetAllocatableMagnitude(ctx, common.HexToAddress(ANVIL_FIRST_ADDRESS), strategyAddr) + assert.NoError(t, err) + + assert.Equal(t, maxmagnitude[0], allocable) + }) } func TestGetCurrentClaimableDistributionRoot(t *testing.T) { From f189b5d525ed92b320757f0bfc4d655a3a5d5528 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Tue, 14 Jan 2025 11:26:11 -0300 Subject: [PATCH 02/21] Add GetOperatorShares test --- chainio/clients/elcontracts/reader_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index 7ff6d87c..ead45952 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -175,6 +175,20 @@ func TestChainReader(t *testing.T) { assert.Equal(t, maxmagnitude[0], allocable) }) + + t.Run("GetOperatorShares", func(t *testing.T) { + // Maybe could add more strategies + strategyAddr := contractAddrs.Erc20MockStrategy + strategies := []common.Address{strategyAddr} + shares, err := clients.ElChainReader.GetOperatorShares( + ctx, + common.HexToAddress(operator.Address), + strategies, + ) + assert.NoError(t, err) + assert.NotZero(t, shares) + }) + } func TestGetCurrentClaimableDistributionRoot(t *testing.T) { From 5c8805f698f586daa0655c0ff4fdaa936c750ee2 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Tue, 14 Jan 2025 11:29:17 -0300 Subject: [PATCH 03/21] Add GetOperatorsShares test --- chainio/clients/elcontracts/reader_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index ead45952..8eae73c6 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -189,6 +189,20 @@ func TestChainReader(t *testing.T) { assert.NotZero(t, shares) }) + t.Run("GetOperatorsShares", func(t *testing.T) { + // Maybe could add more operators and strategies + operatorAddrs := []common.Address{common.HexToAddress(operator.Address)} + strategyAddr := contractAddrs.Erc20MockStrategy + strategies := []common.Address{strategyAddr} + shares, err := clients.ElChainReader.GetOperatorsShares( + ctx, + operatorAddrs, + strategies, + ) + assert.NoError(t, err) + assert.NotZero(t, shares) + }) + } func TestGetCurrentClaimableDistributionRoot(t *testing.T) { From fc87db0766d07d9b6e9a7f6d3a91f0ebed531673 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Tue, 14 Jan 2025 11:29:34 -0300 Subject: [PATCH 04/21] Add simple GetOperatorSetsForOperator test case --- chainio/clients/elcontracts/reader_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index 8eae73c6..b0a26b12 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -203,6 +203,15 @@ func TestChainReader(t *testing.T) { assert.NotZero(t, shares) }) + t.Run("GetOperatorSetsForOperator", func(t *testing.T) { + // GetOperatorSetsForOperator with an operator without sets returns an empty list + operatorSet, err := clients.ElChainReader.GetOperatorSetsForOperator( + ctx, + common.HexToAddress(operator.Address), + ) + assert.NoError(t, err) + assert.Empty(t, operatorSet) + }) } func TestGetCurrentClaimableDistributionRoot(t *testing.T) { From 1cb3ba5dc0b74f20a5c9f69a4391cff7d4043542 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Wed, 15 Jan 2025 11:58:34 -0300 Subject: [PATCH 05/21] Use ReceiptStatusSuccessful constant from gethtypes --- chainio/clients/elcontracts/reader_test.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index bb6d1afb..0bf0a71d 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -13,6 +13,7 @@ import ( "github.com/Layr-Labs/eigensdk-go/types" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -236,7 +237,7 @@ func TestGetCurrentClaimableDistributionRoot(t *testing.T) { // Set delay to zero to inmediatly operate with coordinator receipt, err := setTestRewardsCoordinatorActivationDelay(anvilHttpEndpoint, ecdsaPrivKeyHex, uint32(0)) require.NoError(t, err) - require.Equal(t, receipt.Status, uint64(1)) + require.Equal(t, receipt.Status, gethtypes.ReceiptStatusSuccessful) // Create txManager to send transactions to the Ethereum node txManager, err := testclients.NewTestTxManager(anvilHttpEndpoint, ecdsaPrivKeyHex) @@ -303,7 +304,7 @@ func TestGetRootIndexFromRootHash(t *testing.T) { // Set delay to zero to inmediatly operate with coordinator receipt, err := setTestRewardsCoordinatorActivationDelay(anvilHttpEndpoint, ecdsaPrivKeyHex, uint32(0)) require.NoError(t, err) - require.Equal(t, receipt.Status, uint64(1)) + require.Equal(t, receipt.Status, gethtypes.ReceiptStatusSuccessful) // Create txManager to send transactions to the Ethereum node txManager, err := testclients.NewTestTxManager(anvilHttpEndpoint, ecdsaPrivKeyHex) @@ -403,7 +404,7 @@ func TestGetCumulativeClaimedRewards(t *testing.T) { // 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 == uint64(1)) + require.True(t, receipt.Status == gethtypes.ReceiptStatusSuccessful) strategyAddr := contractAddrs.Erc20MockStrategy strategy, contractUnderlyingToken, underlyingTokenAddr, err := clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( @@ -429,7 +430,7 @@ func TestGetCumulativeClaimedRewards(t *testing.T) { earner := common.HexToAddress("0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6") receipt, err = chainWriter.ProcessClaim(context.Background(), *claim, earner, true) require.NoError(t, err) - require.True(t, receipt.Status == uint64(1)) + require.True(t, receipt.Status == gethtypes.ReceiptStatusSuccessful) // This tests that with a claim result is cumulativeEarnings claimed, err = chainReader.GetCumulativeClaimed(ctx, anvil_address, underlyingTokenAddr) @@ -461,7 +462,7 @@ func TestCheckClaim(t *testing.T) { // 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 == uint64(1)) + require.True(t, receipt.Status == gethtypes.ReceiptStatusSuccessful) cumulativeEarnings := int64(45) claim, err := newTestClaim(chainReader, anvilHttpEndpoint, cumulativeEarnings, privateKeyHex) @@ -470,7 +471,7 @@ func TestCheckClaim(t *testing.T) { earner := common.HexToAddress("0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6") receipt, err = chainWriter.ProcessClaim(context.Background(), *claim, earner, true) require.NoError(t, err) - require.True(t, receipt.Status == uint64(1)) + require.True(t, receipt.Status == gethtypes.ReceiptStatusSuccessful) strategyAddr := contractAddrs.Erc20MockStrategy strategy, contractUnderlyingToken, underlyingTokenAddr, err := clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( From 5af43b43bf209399db3e6dbca95491c2c32943fe Mon Sep 17 00:00:00 2001 From: Madhur Shrimal Date: Wed, 15 Jan 2025 09:18:49 -0800 Subject: [PATCH 06/21] feat: bls signer abstraction (#403) --- crypto/bls/attestation.go | 12 ++ signer/README.md | 19 --- signer/basic_signer.go | 188 ----------------------- signer/bls/cerberus/cerberus.go | 128 +++++++++++++++ signer/bls/cerberus/cerberus_test.go | 19 +++ signer/bls/local/local.go | 63 ++++++++ signer/bls/local/local_test.go | 70 +++++++++ signer/bls/local/testdata/test.bls.json | 1 + signer/bls/privatekey/privatekey.go | 62 ++++++++ signer/bls/privatekey/privatekey_test.go | 65 ++++++++ signer/bls/signer.go | 60 ++++++++ signer/bls/types/errors.go | 8 + signer/bls/types/types.go | 38 +++++ signer/gen.go | 3 - signer/go.mod | 42 +++++ signer/go.sum | 148 ++++++++++++++++++ signer/mockdata/dummy.key.json | 1 - signer/mocks/signer.go | 72 --------- signer/privatekey_signer.go | 71 --------- signer/privatekey_signer_test.go | 88 ----------- signer/signer.go | 22 --- 21 files changed, 716 insertions(+), 464 deletions(-) delete mode 100644 signer/README.md delete mode 100644 signer/basic_signer.go create mode 100644 signer/bls/cerberus/cerberus.go create mode 100644 signer/bls/cerberus/cerberus_test.go create mode 100644 signer/bls/local/local.go create mode 100644 signer/bls/local/local_test.go create mode 100644 signer/bls/local/testdata/test.bls.json create mode 100644 signer/bls/privatekey/privatekey.go create mode 100644 signer/bls/privatekey/privatekey_test.go create mode 100644 signer/bls/signer.go create mode 100644 signer/bls/types/errors.go create mode 100644 signer/bls/types/types.go delete mode 100644 signer/gen.go create mode 100644 signer/go.mod create mode 100644 signer/go.sum delete mode 100644 signer/mockdata/dummy.key.json delete mode 100644 signer/mocks/signer.go delete mode 100644 signer/privatekey_signer.go delete mode 100644 signer/privatekey_signer_test.go delete mode 100644 signer/signer.go diff --git a/crypto/bls/attestation.go b/crypto/bls/attestation.go index 4de764d5..77ec287f 100644 --- a/crypto/bls/attestation.go +++ b/crypto/bls/attestation.go @@ -13,7 +13,10 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fp" "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" ) // We are using similar structure for saving bls keys as ethereum keystore @@ -282,3 +285,12 @@ func (k *KeyPair) GetPubKeyG2() *G2Point { func (k *KeyPair) GetPubKeyG1() *G1Point { return k.PubKey } + +// GetOperatorID hashes the G1Point (public key of an operator) to generate the operator ID. +// It does it to match how it's hashed in solidity: `keccak256(abi.encodePacked(pk.X, pk.Y))` +// Ref: https://github.com/Layr-Labs/eigenlayer-contracts/blob/avs-unstable/src/contracts/libraries/BN254.sol#L285 +func (p *G1Point) GetOperatorID() string { + x := p.X.BigInt(new(big.Int)) + y := p.Y.BigInt(new(big.Int)) + return crypto.Keccak256Hash(append(math.U256Bytes(x), math.U256Bytes(y)...)).Hex() +} diff --git a/signer/README.md b/signer/README.md deleted file mode 100644 index a7057dab..00000000 --- a/signer/README.md +++ /dev/null @@ -1,19 +0,0 @@ -## Signer - -> [!WARNING] -> signer is deprecated. Please use [signerv2](../signerv2/README.md) instead. - -This module is used for initializing the signer used to sign smart contract transactions. - -There are two types of signer we support -#### Private Key signer -This expects an ECDSA key as argument -``` -signer, err := NewPrivateKeySigner(privateKey, chainID) -``` - -#### Private key from local keystore -This expects a local path to encrypted ECDSA key json file and password to decrypt it. -``` -signer, err := NewPrivateKeyFromKeystoreSigner(path, password, chainID) -``` \ No newline at end of file diff --git a/signer/basic_signer.go b/signer/basic_signer.go deleted file mode 100644 index 8ff440bb..00000000 --- a/signer/basic_signer.go +++ /dev/null @@ -1,188 +0,0 @@ -package signer - -import ( - "context" - "crypto/ecdsa" - "fmt" - "math/big" - - "github.com/Layr-Labs/eigensdk-go/logging" - "github.com/Layr-Labs/eigensdk-go/utils" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - gethcommon "github.com/ethereum/go-ethereum/common" - gethtypes "github.com/ethereum/go-ethereum/core/types" -) - -// exported as the default so that users can call NewBasicSigner with it if they don't know any better -var FallbackGasTipCap = big.NewInt(15000000000) - -type ethClient interface { - bind.ContractBackend - - ChainID(ctx context.Context) (*big.Int, error) - TransactionReceipt(ctx context.Context, txHash gethcommon.Hash) (*gethtypes.Receipt, error) -} - -// Deprecated: Use SignerV2 instead -type BasicSigner struct { - logger logging.Logger - ethClient ethClient - privateKey *ecdsa.PrivateKey - accountAddress gethcommon.Address - contracts map[gethcommon.Address]*bind.BoundContract - fallbackGasTipCap *big.Int -} - -func NewBasicSigner( - privateKey *ecdsa.PrivateKey, - client ethClient, - logger logging.Logger, - fallbackGasTipCap *big.Int, -) (*BasicSigner, error) { - - accountAddress, err := utils.EcdsaPrivateKeyToAddress(privateKey) - if err != nil { - return nil, utils.WrapError("Cannot get account address", err) - } - - return &BasicSigner{ - logger: logger, - ethClient: client, - privateKey: privateKey, - accountAddress: accountAddress, - contracts: make(map[gethcommon.Address]*bind.BoundContract), - fallbackGasTipCap: fallbackGasTipCap, - }, nil -} - -// TODO: is this the right place to put this? -// -// it's needed when making calls calls using the bindings, eg -// AvsContractBindings.TaskManager.CreateNewTask(w.NoSendTransactOpts, numToSquare) -func (s *BasicSigner) GetNoSendTransactOpts() (*bind.TransactOpts, error) { - chainIDBigInt, err := s.ethClient.ChainID(context.Background()) - if err != nil { - return nil, utils.WrapError("Cannot get chainId", err) - } - opts, err := bind.NewKeyedTransactorWithChainID(s.privateKey, chainIDBigInt) - if err != nil { - return nil, utils.WrapError("Cannot create NoSendTransactOpts", err) - } - opts.NoSend = true - return opts, nil -} - -// EstimateGasPriceAndLimitAndSendTx sends and returns an otherwise identical txn -// to the one provided but with updated gas prices sampled from the existing network -// conditions and an accurate gasLimit -// -// Note: tx must be a to a contract, not an EOA -// -// Slightly modified from: -// https://github.com/ethereum-optimism/optimism/blob/ec266098641820c50c39c31048aa4e953bece464/batch-submitter/drivers/sequencer/driver.go#L314 -func (s *BasicSigner) EstimateGasPriceAndLimitAndSendTx( - ctx context.Context, - tx *gethtypes.Transaction, - tag string, -) (*gethtypes.Receipt, error) { - s.logger.Debug("Entering EstimateGasPriceAndLimitAndSendTx function...") - defer s.logger.Debug("Exiting EstimateGasPriceAndLimitAndSendTx function...") - - gasTipCap, err := s.ethClient.SuggestGasTipCap(ctx) - if err != nil { - // If the transaction failed because the backend does not support - // eth_maxPriorityFeePerGas, fallback to using the default constant. - // Currently Alchemy is the only backend provider that exposes this - // method, so in the event their API is unreachable we can fallback to a - // degraded mode of operation. This also applies to our test - // environments, as hardhat doesn't support the query either. - s.logger.Info("eth_maxPriorityFeePerGas is unsupported by current backend, using fallback gasTipCap") - gasTipCap = s.fallbackGasTipCap - } - - header, err := s.ethClient.HeaderByNumber(ctx, nil) - if err != nil { - return nil, err - } - gasFeeCap := new(big.Int).Add(header.BaseFee, gasTipCap) - - // The estimated gas limits performed by RawTransact fail semi-regularly - // with out of gas exceptions. To remedy this we extract the internal calls - // to perform gas price/gas limit estimation here and add a buffer to - // account for any network variability. - gasLimit, err := s.ethClient.EstimateGas(ctx, ethereum.CallMsg{ - From: s.accountAddress, - To: tx.To(), - GasTipCap: gasTipCap, - GasFeeCap: gasFeeCap, - Value: nil, - Data: tx.Data(), - }) - - if err != nil { - return nil, err - } - - opts, err := bind.NewKeyedTransactorWithChainID(s.privateKey, tx.ChainId()) - if err != nil { - return nil, utils.WrapError("Cannot create transactOpts", err) - } - opts.Context = ctx - opts.Nonce = new(big.Int).SetUint64(tx.Nonce()) - opts.GasTipCap = gasTipCap - opts.GasFeeCap = gasFeeCap - opts.GasLimit = addGasBuffer(gasLimit) - - contract := s.contracts[*tx.To()] - // if the contract has not been cached - if contract == nil { - // create a dummy bound contract tied to the `to` address of the transaction - contract = bind.NewBoundContract(*tx.To(), abi.ABI{}, s.ethClient, s.ethClient, s.ethClient) - // cache the contract for later use - s.contracts[*tx.To()] = contract - } - - tx, err = contract.RawTransact(opts, tx.Data()) - if err != nil { - return nil, utils.WrapError(fmt.Errorf("Failed to send transaction with tag: %v", tag), err) - } - - receipt, err := s.EnsureTransactionEvaled( - tx, - tag, - ) - if err != nil { - return nil, err - } - - return receipt, err -} - -func (s *BasicSigner) EnsureTransactionEvaled(tx *gethtypes.Transaction, tag string) (*gethtypes.Receipt, error) { - receipt, err := bind.WaitMined(context.Background(), s.ethClient, tx) - if err != nil { - return nil, utils.WrapError(fmt.Errorf("Failed to wait for transaction to mine with tag: %v", tag), err) - } - if receipt.Status != 1 { - return nil, fmt.Errorf( - "Transaction failed (tag: %v, txHash: %v, status: %v, gasUsed: %v)", - tag, - tx.Hash().Hex(), - receipt.Status, - receipt.GasUsed, - ) - } - s.logger.Debug("successfully submitted transaction", - "txHash", receipt.TxHash.Hex(), - "tag", tag, - "gasUsed", receipt.GasUsed, - ) - return receipt, nil -} - -func addGasBuffer(gasLimit uint64) uint64 { - return 6 * gasLimit / 5 // add 20% buffer to gas limit -} diff --git a/signer/bls/cerberus/cerberus.go b/signer/bls/cerberus/cerberus.go new file mode 100644 index 00000000..c8b87db8 --- /dev/null +++ b/signer/bls/cerberus/cerberus.go @@ -0,0 +1,128 @@ +package cerberus + +import ( + "context" + "encoding/hex" + "fmt" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + + sdkBls "github.com/Layr-Labs/eigensdk-go/crypto/bls" + "github.com/Layr-Labs/eigensdk-go/signer/bls/types" + "github.com/consensys/gnark-crypto/ecc/bn254" + + v1 "github.com/Layr-Labs/cerberus-api/pkg/api/v1" +) + +type Config struct { + URL string + PublicKeyHex string + + // Optional: in case if your signer uses local keystore + Password string + + EnableTLS bool + TLSCertFilePath string + + SigningTimeout time.Duration +} + +type Signer struct { + signerClient v1.SignerClient + kmsClient v1.KeyManagerClient + pubKeyHex string + password string +} + +func New(cfg Config) (Signer, error) { + opts := make([]grpc.DialOption, 0) + if cfg.EnableTLS { + creds, err := credentials.NewClientTLSFromFile(cfg.TLSCertFilePath, "") + if err != nil { + return Signer{}, fmt.Errorf("could not load tls cert: %w", err) + } + opts = append(opts, grpc.WithTransportCredentials(creds)) + } else { + opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) + } + + conn, err := grpc.NewClient(cfg.URL, opts...) + if err != nil { + return Signer{}, fmt.Errorf("did not connect: %w", err) + } + + signerClient := v1.NewSignerClient(conn) + kmsClient := v1.NewKeyManagerClient(conn) + return Signer{ + signerClient: signerClient, + kmsClient: kmsClient, + pubKeyHex: cfg.PublicKeyHex, + password: cfg.Password, + }, nil +} + +func (s Signer) Sign(ctx context.Context, msg []byte) ([]byte, error) { + if len(msg) != 32 { + return nil, types.ErrInvalidMessageLength + } + + resp, err := s.signerClient.SignGeneric(ctx, &v1.SignGenericRequest{ + Data: msg, + PublicKeyG1: s.pubKeyHex, + Password: s.password, + }) + if err != nil { + return nil, err + } + + return resp.Signature, nil +} + +func (s Signer) SignG1(ctx context.Context, msg []byte) ([]byte, error) { + if len(msg) != 64 { + return nil, types.ErrInvalidMessageLength + } + + resp, err := s.signerClient.SignG1(ctx, &v1.SignG1Request{ + Data: msg, + PublicKeyG1: s.pubKeyHex, + Password: s.password, + }) + if err != nil { + return nil, err + } + + return resp.Signature, nil +} + +func (s Signer) GetOperatorId() (string, error) { + pkBytes, err := hex.DecodeString(s.pubKeyHex) + if err != nil { + return "", fmt.Errorf("failed to decode BLS public key: %w", err) + } + var point bn254.G1Affine + _, err = point.SetBytes(pkBytes) + if err != nil { + return "", fmt.Errorf("failed to set BLS public key: %w", err) + } + pubkey := &sdkBls.G1Point{G1Affine: &point} + return pubkey.GetOperatorID(), nil +} + +func (s Signer) GetPublicKeyG1() string { + return s.pubKeyHex +} + +func (s Signer) GetPublicKeyG2() string { + resp, err := s.kmsClient.GetKeyMetadata(context.Background(), &v1.GetKeyMetadataRequest{ + PublicKeyG1: s.pubKeyHex, + }) + if err != nil { + return "" + } + + return resp.PublicKeyG2 +} diff --git a/signer/bls/cerberus/cerberus_test.go b/signer/bls/cerberus/cerberus_test.go new file mode 100644 index 00000000..5878eab2 --- /dev/null +++ b/signer/bls/cerberus/cerberus_test.go @@ -0,0 +1,19 @@ +package cerberus + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: add test for cerberus when the docker is released + +func TestOperatorId(t *testing.T) { + signer := Signer{ + pubKeyHex: "dc8f9427033e5ff392f5cc97cc3d6a5472cff2778eee0961a497bd7dbb629a36", + } + + operatorId, err := signer.GetOperatorId() + assert.NoError(t, err) + assert.Equal(t, operatorId, "0x2f6d54c4ef253d4ac1b6bfa672a8f449a0aa6ab1c20ee97a74f8e521fe57604b") +} diff --git a/signer/bls/local/local.go b/signer/bls/local/local.go new file mode 100644 index 00000000..84425dd5 --- /dev/null +++ b/signer/bls/local/local.go @@ -0,0 +1,63 @@ +package local + +import ( + "context" + "encoding/hex" + + sdkBls "github.com/Layr-Labs/eigensdk-go/crypto/bls" + "github.com/Layr-Labs/eigensdk-go/signer/bls/types" +) + +type Config struct { + Path string + Password string +} + +type Signer struct { + key *sdkBls.KeyPair +} + +func New(cfg Config) (*Signer, error) { + keyPair, err := sdkBls.ReadPrivateKeyFromFile(cfg.Path, cfg.Password) + if err != nil { + return nil, err + } + return &Signer{ + key: keyPair, + }, nil +} + +func (s Signer) Sign(ctx context.Context, msg []byte) ([]byte, error) { + if len(msg) != 32 { + return nil, types.ErrInvalidMessageLength + } + + var data [32]byte + copy(data[:], msg) + + return s.key.SignMessage(data).Serialize(), nil +} + +func (s Signer) SignG1(ctx context.Context, msg []byte) ([]byte, error) { + if len(msg) != 64 { + return nil, types.ErrInvalidMessageLength + } + + msgG1 := new(sdkBls.G1Point) + msgG1 = msgG1.Deserialize(msg) + return s.key.SignHashedToCurveMessage(msgG1.G1Affine).Serialize(), nil +} + +func (s Signer) GetOperatorId() (string, error) { + return s.key.PubKey.GetOperatorID(), nil +} + +func (s Signer) GetPublicKeyG1() string { + rawBytes := s.key.PubKey.Bytes() + return hex.EncodeToString(rawBytes[:]) +} + +func (s Signer) GetPublicKeyG2() string { + rawBytes := s.key.GetPubKeyG2().Bytes() + return hex.EncodeToString(rawBytes[:]) +} diff --git a/signer/bls/local/local_test.go b/signer/bls/local/local_test.go new file mode 100644 index 00000000..076c73da --- /dev/null +++ b/signer/bls/local/local_test.go @@ -0,0 +1,70 @@ +package local + +import ( + "context" + "encoding/hex" + "testing" + + "github.com/stretchr/testify/assert" +) + +// empty password for local testing +const password = "" + +func TestOperatorId(t *testing.T) { + signer, err := New(Config{ + Path: "testdata/test.bls.json", + Password: password, + }) + assert.NoError(t, err) + + operatorId, err := signer.GetOperatorId() + assert.NoError(t, err) + assert.Equal(t, operatorId, "0x2f6d54c4ef253d4ac1b6bfa672a8f449a0aa6ab1c20ee97a74f8e521fe57604b") +} + +func TestPublicKeyG1(t *testing.T) { + signer, err := New(Config{ + Path: "testdata/test.bls.json", + Password: password, + }) + assert.NoError(t, err) + + pubKeyG1 := signer.GetPublicKeyG1() + assert.Equal(t, pubKeyG1, "dc8f9427033e5ff392f5cc97cc3d6a5472cff2778eee0961a497bd7dbb629a36") +} + +func TestPublicKeyG2(t *testing.T) { + signer, err := New(Config{ + Path: "testdata/test.bls.json", + Password: password, + }) + assert.NoError(t, err) + + pubKeyG2 := signer.GetPublicKeyG2() + assert.Equal( + t, + pubKeyG2, + "e9b0f889a847f8dc2ed0514a6b7e11043679491052502e0a68ccc9a410f524e01e9d4863b49ca41d0a94928290b15aed25bfe097e266bdbb9106a09f689b4ea8", + ) +} + +func TestSign(t *testing.T) { + signer, err := New(Config{ + Path: "testdata/test.bls.json", + Password: password, + }) + assert.NoError(t, err) + + msg := [32]byte{} + copy(msg[:], []byte("hello")) + + signature, err := signer.Sign(context.Background(), msg[:]) + signatureHex := hex.EncodeToString(signature) + assert.NoError(t, err) + assert.Equal( + t, + signatureHex, + "2a21c157c51d13aa5922f67751520287088aa5336ae6d2ba06d0423fe7166ed811b48b5a3ff129d4c645f5f4cb33177a3503e26dc2d508b4b943bb8dd45085e2", + ) +} diff --git a/signer/bls/local/testdata/test.bls.json b/signer/bls/local/testdata/test.bls.json new file mode 100644 index 00000000..2d77cf94 --- /dev/null +++ b/signer/bls/local/testdata/test.bls.json @@ -0,0 +1 @@ +{"pubKey":"E([12918441400833609239596509389345925094276410981682612875742259377217210587702,11932086071418014723502613555349302846398037390325467678628891156883964756680])","crypto":{"cipher":"aes-128-ctr","ciphertext":"42b29d79554441b3c08936a1796929196e59ba9328feaa10441c91be51afd987","cipherparams":{"iv":"13857599ccf21566a5fb960290c20722"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"c0d4f3214d3774751072ca6952a38e4096d6f1131bd60a945e75a2a1e80b5715"},"mac":"49af4e5cdee5089bfbb396fa30cb8ece4e2e57485d2f61e67ef218f0ff7cda07"}} \ No newline at end of file diff --git a/signer/bls/privatekey/privatekey.go b/signer/bls/privatekey/privatekey.go new file mode 100644 index 00000000..09b7826a --- /dev/null +++ b/signer/bls/privatekey/privatekey.go @@ -0,0 +1,62 @@ +package privatekey + +import ( + "context" + "encoding/hex" + + sdkBls "github.com/Layr-Labs/eigensdk-go/crypto/bls" + "github.com/Layr-Labs/eigensdk-go/signer/bls/types" +) + +type Config struct { + PrivateKey string +} + +type Signer struct { + key *sdkBls.KeyPair +} + +func New(cfg Config) (*Signer, error) { + keyPair, err := sdkBls.NewKeyPairFromString(cfg.PrivateKey) + if err != nil { + return nil, err + } + return &Signer{ + key: keyPair, + }, nil +} + +func (s Signer) Sign(ctx context.Context, msg []byte) ([]byte, error) { + if len(msg) != 32 { + return nil, types.ErrInvalidMessageLength + } + + var data [32]byte + copy(data[:], msg) + + return s.key.SignMessage(data).Serialize(), nil +} + +func (s Signer) SignG1(ctx context.Context, msg []byte) ([]byte, error) { + if len(msg) != 64 { + return nil, types.ErrInvalidMessageLength + } + + msgG1 := new(sdkBls.G1Point) + msgG1 = msgG1.Deserialize(msg) + return s.key.SignHashedToCurveMessage(msgG1.G1Affine).Serialize(), nil +} + +func (s Signer) GetOperatorId() (string, error) { + return s.key.PubKey.GetOperatorID(), nil +} + +func (s Signer) GetPublicKeyG1() string { + rawBytes := s.key.PubKey.Bytes() + return hex.EncodeToString(rawBytes[:]) +} + +func (s Signer) GetPublicKeyG2() string { + rawBytes := s.key.GetPubKeyG2().Bytes() + return hex.EncodeToString(rawBytes[:]) +} diff --git a/signer/bls/privatekey/privatekey_test.go b/signer/bls/privatekey/privatekey_test.go new file mode 100644 index 00000000..f0fc7437 --- /dev/null +++ b/signer/bls/privatekey/privatekey_test.go @@ -0,0 +1,65 @@ +package privatekey + +import ( + "context" + "encoding/hex" + "testing" + + "github.com/stretchr/testify/assert" +) + +const privateKey = "13718104057011380243349384062412322292853638010146548074368241565852610884213" + +func TestOperatorId(t *testing.T) { + signer, err := New(Config{ + PrivateKey: privateKey, + }) + assert.NoError(t, err) + + operatorId, err := signer.GetOperatorId() + assert.NoError(t, err) + assert.Equal(t, operatorId, "0x2f6d54c4ef253d4ac1b6bfa672a8f449a0aa6ab1c20ee97a74f8e521fe57604b") +} + +func TestPublicKeyG1(t *testing.T) { + signer, err := New(Config{ + PrivateKey: privateKey, + }) + assert.NoError(t, err) + + pubKeyG1 := signer.GetPublicKeyG1() + assert.Equal(t, pubKeyG1, "0xdc8f9427033e5ff392f5cc97cc3d6a5472cff2778eee0961a497bd7dbb629a36") +} + +func TestPublicKeyG2(t *testing.T) { + signer, err := New(Config{ + PrivateKey: privateKey, + }) + assert.NoError(t, err) + + pubKeyG2 := signer.GetPublicKeyG2() + assert.Equal( + t, + pubKeyG2, + "0xe9b0f889a847f8dc2ed0514a6b7e11043679491052502e0a68ccc9a410f524e01e9d4863b49ca41d0a94928290b15aed25bfe097e266bdbb9106a09f689b4ea8", + ) +} + +func TestSign(t *testing.T) { + signer, err := New(Config{ + PrivateKey: privateKey, + }) + assert.NoError(t, err) + + msg := [32]byte{} + copy(msg[:], []byte("hello")) + + signature, err := signer.Sign(context.Background(), msg[:]) + signatureHex := hex.EncodeToString(signature) + assert.NoError(t, err) + assert.Equal( + t, + signatureHex, + "2a21c157c51d13aa5922f67751520287088aa5336ae6d2ba06d0423fe7166ed811b48b5a3ff129d4c645f5f4cb33177a3503e26dc2d508b4b943bb8dd45085e2", + ) +} diff --git a/signer/bls/signer.go b/signer/bls/signer.go new file mode 100644 index 00000000..ccbcb1d2 --- /dev/null +++ b/signer/bls/signer.go @@ -0,0 +1,60 @@ +package bls + +import ( + "context" + + "github.com/Layr-Labs/eigensdk-go/signer/bls/cerberus" + "github.com/Layr-Labs/eigensdk-go/signer/bls/local" + "github.com/Layr-Labs/eigensdk-go/signer/bls/privatekey" + "github.com/Layr-Labs/eigensdk-go/signer/bls/types" +) + +type Signer interface { + // Sign signs the message using the BLS signature scheme + Sign(ctx context.Context, msg []byte) ([]byte, error) + + // SignG1 signs the message using the BLS signature scheme + // This message is assumed to be already mapped to G1 point + SignG1(ctx context.Context, msg []byte) ([]byte, error) + + // GetOperatorId returns the operator ID of the signer. + // This is hash of the G1 public key of the signer + GetOperatorId() (string, error) + + GetPublicKeyG1() string + + GetPublicKeyG2() string +} + +// NewSigner creates a new Signer instance based on the provided configuration. +// It supports different types of signers, such as Local and Cerberus. +// +// Parameters: +// - cfg: A SignerConfig struct that contains the configuration for the signer. +// +// Returns: +// - Signer: An instance of the Signer interface. +// - error: An error if the signer type is invalid or if there is an issue creating the signer. +func NewSigner(cfg types.SignerConfig) (Signer, error) { + switch cfg.SignerType { + case types.Local: + return local.New(local.Config{ + Path: cfg.Path, + Password: cfg.Password, + }) + case types.Cerberus: + return cerberus.New(cerberus.Config{ + URL: cfg.CerberusUrl, + PublicKeyHex: cfg.PublicKeyHex, + Password: cfg.CerberusPassword, + EnableTLS: cfg.EnableTLS, + TLSCertFilePath: cfg.TLSCertFilePath, + }) + case types.PrivateKey: + return privatekey.New(privatekey.Config{ + PrivateKey: cfg.PrivateKey, + }) + default: + return nil, types.ErrInvalidSignerType + } +} diff --git a/signer/bls/types/errors.go b/signer/bls/types/errors.go new file mode 100644 index 00000000..e53631ae --- /dev/null +++ b/signer/bls/types/errors.go @@ -0,0 +1,8 @@ +package types + +import "errors" + +var ( + ErrInvalidMessageLength = errors.New("invalid message length. must be 32 bytes") + ErrInvalidSignerType = errors.New("invalid signer type") +) diff --git a/signer/bls/types/types.go b/signer/bls/types/types.go new file mode 100644 index 00000000..8a3e9fa7 --- /dev/null +++ b/signer/bls/types/types.go @@ -0,0 +1,38 @@ +package types + +type SignerType string + +const ( + // Local signer type + Local SignerType = "local" + // Cerberus signer type + Cerberus SignerType = "cerberus" + // PrivateKey signer type + PrivateKey SignerType = "privatekey" +) + +type SignerConfig struct { + // PrivateKey is the private key of the signer + PrivateKey string + + // Type of the signer + SignerType SignerType + + // Params for local signer + // Path to the key file + Path string + // Password to decrypt the key file + Password string + + // Params for cerberus signer + // CerberusUrl of the cerberus signer + CerberusUrl string + // PublicKeyHex is the public key of the cerberus signer + PublicKeyHex string + // CerberusPassword is the password to encrypt the key if cerberus using local keystore + CerberusPassword string + // EnableTLS enables TLS for the cerberus signer + EnableTLS bool + // TLSCertFilePath is the path to the TLS cert file + TLSCertFilePath string +} diff --git a/signer/gen.go b/signer/gen.go deleted file mode 100644 index b85daadf..00000000 --- a/signer/gen.go +++ /dev/null @@ -1,3 +0,0 @@ -package signer - -//go:generate mockgen -destination=./mocks/signer.go -package=mocks github.com/Layr-Labs/eigensdk-go/signer Signer diff --git a/signer/go.mod b/signer/go.mod new file mode 100644 index 00000000..34d47dc2 --- /dev/null +++ b/signer/go.mod @@ -0,0 +1,42 @@ +module github.com/Layr-Labs/eigensdk-go/signer + +go 1.21.13 + +replace github.com/Layr-Labs/eigensdk-go => ../../eigensdk-go + +require ( + github.com/Layr-Labs/cerberus-api v0.0.2-0.20250108174619-d5e1eb03fbd5 + github.com/Layr-Labs/eigensdk-go v0.1.13 + github.com/stretchr/testify v1.9.0 + google.golang.org/grpc v1.64.1 +) + +require ( + github.com/bits-and-blooms/bitset v1.10.0 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect + github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/deckarep/golang-set/v2 v2.1.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/ethereum/c-kzg-4844 v1.0.0 // indirect + github.com/ethereum/go-ethereum v1.14.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect + github.com/holiman/uint256 v1.2.4 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/supranational/blst v0.3.11 // indirect + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.17.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + rsc.io/tmplfunc v0.0.3 // indirect +) diff --git a/signer/go.sum b/signer/go.sum new file mode 100644 index 00000000..873dadf4 --- /dev/null +++ b/signer/go.sum @@ -0,0 +1,148 @@ +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/cerberus-api v0.0.2-0.20250108174619-d5e1eb03fbd5 h1:s24M6HYObEuV9OSY36jUM09kp5fOhuz/g1ev2qWDPzU= +github.com/Layr-Labs/cerberus-api v0.0.2-0.20250108174619-d5e1eb03fbd5/go.mod h1:Lm4fhzy0S3P7GjerzuseGaBFVczsIKmEhIjcT52Hluo= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= +github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= +github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v1.1.0 h1:pcFh8CdCIt2kmEpK0OIatq67Ln9uGDYY3d5XnE0LJG4= +github.com/cockroachdb/pebble v1.1.0/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= +github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= +github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= +github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.14.0 h1:xRWC5NlB6g1x7vNy4HDBLuqVNbtLrc7v8S6+Uxim1LU= +github.com/ethereum/go-ethereum v1.14.0/go.mod h1:1STrq471D0BQbCX9He0hUj4bHxX2k6mt5nOQJhDNOJ8= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= +github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= +github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= +github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/signer/mockdata/dummy.key.json b/signer/mockdata/dummy.key.json deleted file mode 100644 index f9a4685e..00000000 --- a/signer/mockdata/dummy.key.json +++ /dev/null @@ -1 +0,0 @@ -{"address":"d4ee935d77b590aa64aed7b02dd66f1383006684","crypto":{"cipher":"aes-128-ctr","ciphertext":"10eca95bf52cb5baab31cb49045ddbe9bcb00b6e91564d5116ca85033577576e","cipherparams":{"iv":"7ab87b9ea99fcb66e7228d8ab49ae941"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"7712a47bbd000afcb603c9bb9fb06125a117fa34b34c7770aee03f22b7179648"},"mac":"2a4dea47769b5707382403378a92e61d2a182860438e1cbceac35117b0d1e482"},"id":"11fdd2cd-7f1e-4f31-834c-5fa98d7cd06d","version":3} \ No newline at end of file diff --git a/signer/mocks/signer.go b/signer/mocks/signer.go deleted file mode 100644 index ccaf9cae..00000000 --- a/signer/mocks/signer.go +++ /dev/null @@ -1,72 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/Layr-Labs/eigensdk-go/signer (interfaces: Signer) -// -// Generated by this command: -// -// mockgen -destination=./mocks/signer.go -package=mocks github.com/Layr-Labs/eigensdk-go/signer Signer -// - -// Package mocks is a generated GoMock package. -package mocks - -import ( - context "context" - reflect "reflect" - - bind "github.com/ethereum/go-ethereum/accounts/abi/bind" - common "github.com/ethereum/go-ethereum/common" - types "github.com/ethereum/go-ethereum/core/types" - gomock "go.uber.org/mock/gomock" -) - -// MockSigner is a mock of Signer interface. -type MockSigner struct { - ctrl *gomock.Controller - recorder *MockSignerMockRecorder -} - -// MockSignerMockRecorder is the mock recorder for MockSigner. -type MockSignerMockRecorder struct { - mock *MockSigner -} - -// NewMockSigner creates a new mock instance. -func NewMockSigner(ctrl *gomock.Controller) *MockSigner { - mock := &MockSigner{ctrl: ctrl} - mock.recorder = &MockSignerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockSigner) EXPECT() *MockSignerMockRecorder { - return m.recorder -} - -// GetTxOpts mocks base method. -func (m *MockSigner) GetTxOpts() *bind.TransactOpts { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTxOpts") - ret0, _ := ret[0].(*bind.TransactOpts) - return ret0 -} - -// GetTxOpts indicates an expected call of GetTxOpts. -func (mr *MockSignerMockRecorder) GetTxOpts() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxOpts", reflect.TypeOf((*MockSigner)(nil).GetTxOpts)) -} - -// SendToExternal mocks base method. -func (m *MockSigner) SendToExternal(arg0 context.Context, arg1 *types.Transaction) (common.Hash, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SendToExternal", arg0, arg1) - ret0, _ := ret[0].(common.Hash) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SendToExternal indicates an expected call of SendToExternal. -func (mr *MockSignerMockRecorder) SendToExternal(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendToExternal", reflect.TypeOf((*MockSigner)(nil).SendToExternal), arg0, arg1) -} diff --git a/signer/privatekey_signer.go b/signer/privatekey_signer.go deleted file mode 100644 index 4e532c5a..00000000 --- a/signer/privatekey_signer.go +++ /dev/null @@ -1,71 +0,0 @@ -package signer - -import ( - "context" - "crypto/ecdsa" - "errors" - "math/big" - "os" - "path/filepath" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" -) - -// Deprecated: Use SignerV2 instead -type PrivateKeySigner struct { - txOpts *bind.TransactOpts -} - -var _ Signer = (*PrivateKeySigner)(nil) - -func NewPrivateKeySigner(privateKey *ecdsa.PrivateKey, chainID *big.Int) (Signer, error) { - // TODO (madhur): chainId should not be hardcoded - txOpts, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID) - if err != nil { - return nil, err - } - return &PrivateKeySigner{ - txOpts: txOpts, - }, nil -} - -func NewPrivateKeyFromKeystoreSigner(path string, password string, chainID *big.Int) (Signer, error) { - privateKey, err := getECDSAPrivateKey(path, password) - if err != nil { - return nil, err - } - - // TODO (madhur): chainId should not be hardcoded - txOpts, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID) - if err != nil { - return nil, err - } - return &PrivateKeySigner{ - txOpts: txOpts, - }, nil -} - -func (p *PrivateKeySigner) GetTxOpts() *bind.TransactOpts { - return p.txOpts -} - -func (p *PrivateKeySigner) SendToExternal(ctx context.Context, tx *types.Transaction) (common.Hash, error) { - return common.Hash{}, errors.New("this signer does not support external signing") -} - -func getECDSAPrivateKey(keyStoreFile string, password string) (*ecdsa.PrivateKey, error) { - keyStoreContents, err := os.ReadFile(filepath.Clean(keyStoreFile)) - if err != nil { - return nil, err - } - - sk, err := keystore.DecryptKey(keyStoreContents, password) - if err != nil { - return nil, err - } - - return sk.PrivateKey, nil -} diff --git a/signer/privatekey_signer_test.go b/signer/privatekey_signer_test.go deleted file mode 100644 index 6f77cf28..00000000 --- a/signer/privatekey_signer_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package signer - -import ( - "crypto/ecdsa" - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/stretchr/testify/assert" -) - -func TestPrivateKeySigner(t *testing.T) { - privateKey, err := crypto.GenerateKey() - assert.NoError(t, err) - - tests := map[string]struct { - privateKey *ecdsa.PrivateKey - chainID *big.Int - success bool - }{ - "Successful initialization": { - privateKey: privateKey, - chainID: big.NewInt(5), - success: true, - }, - "Failure with Invalid network": { - privateKey: privateKey, - success: false, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - _, err := NewPrivateKeySigner(test.privateKey, test.chainID) - if test.success { - assert.NoError(t, err) - return - } else { - assert.Error(t, err) - } - }) - } -} - -func TestPrivateKeyFromKeystoreSigner(t *testing.T) { - tests := map[string]struct { - path string - password string - chainID *big.Int - success bool - }{ - "Successful initialization": { - path: "./mockdata/dummy.key.json", - password: "test12345", - chainID: big.NewInt(5), - success: true, - }, - "Failure with Invalid network": { - path: "./mockdata/dummy.key.json", - password: "test12345", - success: false, - }, - "Failure with Invalid password": { - path: "./mockdata/dummy.key.json", - password: "wrong_password", - chainID: big.NewInt(5), - success: false, - }, - "Failure with unknown path": { - path: "./mockdata/wrongfile.key.json", - password: "test12345", - chainID: big.NewInt(5), - success: false, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - _, err := NewPrivateKeyFromKeystoreSigner(test.path, test.password, test.chainID) - if test.success { - assert.NoError(t, err) - return - } else { - assert.Error(t, err) - } - }) - } -} diff --git a/signer/signer.go b/signer/signer.go deleted file mode 100644 index 1c8573b3..00000000 --- a/signer/signer.go +++ /dev/null @@ -1,22 +0,0 @@ -package signer - -import ( - "context" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" -) - -// Signer is an interface that defines the methods that a signer must implement. -// There are two kinds of signer. -// 1. A signer that can implement a Signer function and return the signed transaction. -// They need to implement GetSigner() function and leave SendToExternal() unimplemented. -// -// 2. A signer (remote signer) that we will send to an external rpc which takes care of signing and broadcasting the -// signed transaction. They need to implement SendToExternal() function and leave GetSigner() unimplemented. -// Deprecated: Use SignerV2 instead -type Signer interface { - GetTxOpts() *bind.TransactOpts - SendToExternal(ctx context.Context, tx *types.Transaction) (common.Hash, error) -} From 78bcc4dbf5c75ce5721ce01e6e7754199483ae31 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Wed, 15 Jan 2025 14:47:20 -0300 Subject: [PATCH 07/21] Improve test that covers getAllocatable and getMax --- chainio/clients/elcontracts/reader_test.go | 107 ++++++++++++++++----- 1 file changed, 83 insertions(+), 24 deletions(-) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index 58664d40..51a1aa5d 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts" + allocationmanager "github.com/Layr-Labs/eigensdk-go/contracts/bindings/AllocationManager" erc20 "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IERC20" rewardscoordinator "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IRewardsCoordinator" "github.com/Layr-Labs/eigensdk-go/testutils" @@ -141,30 +142,6 @@ func TestChainReader(t *testing.T) { assert.Equal(t, address.String(), operator.Address) }) - t.Run("get Allocatable Magnitude", func(t *testing.T) { - // Without changes, Allocable magnitude is max magnitude - - rewardsCoordinatorAddr := contractAddrs.RewardsCoordinator - config := elcontracts.Config{ - DelegationManagerAddress: contractAddrs.DelegationManager, - RewardsCoordinatorAddress: rewardsCoordinatorAddr, - } - - chainReader, err := testclients.NewTestChainReaderFromConfig(anvilHttpEndpoint, config) - require.NoError(t, err) - - strategyAddr := contractAddrs.Erc20MockStrategy - - strategies := []common.Address{strategyAddr} - maxmagnitude, err := chainReader.GetMaxMagnitudes(ctx, common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS), strategies) - assert.NoError(t, err) - - allocable, err := chainReader.GetAllocatableMagnitude(ctx, common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS), strategyAddr) - assert.NoError(t, err) - - assert.Equal(t, maxmagnitude[0], allocable) - }) - t.Run("GetOperatorShares", func(t *testing.T) { // Maybe could add more strategies strategyAddr := contractAddrs.Erc20MockStrategy @@ -488,6 +465,88 @@ func TestCheckClaim(t *testing.T) { assert.True(t, checked) } +func TestGetAllocatableMagnitudeAndGetMaxMagnitudes(t *testing.T) { + // Without changes, Allocable magnitude is max magnitude + + // Test setup + ctx := context.Background() + + testConfig := testutils.GetDefaultTestConfig() + anvilC, err := testutils.StartAnvilContainer(testConfig.AnvilStateFileName) + require.NoError(t, err) + + anvilHttpEndpoint, err := anvilC.Endpoint(context.Background(), "http") + require.NoError(t, err) + contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) + + operatorAddr := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS) + config := elcontracts.Config{ + DelegationManagerAddress: contractAddrs.DelegationManager, + } + + chainReader, err := testclients.NewTestChainReaderFromConfig(anvilHttpEndpoint, config) + require.NoError(t, err) + + strategyAddr := contractAddrs.Erc20MockStrategy + testAddr := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS) + operatorSetId := uint32(1) + + strategies := []common.Address{strategyAddr} + maxmagnitude, err := chainReader.GetMaxMagnitudes(ctx, testAddr, strategies) + assert.NoError(t, err) + + // Assert that at the beginning, Allocatable Magnitude is Max allocatable magnitude + allocable, err := chainReader.GetAllocatableMagnitude(ctx, testAddr, strategyAddr) + assert.NoError(t, err) + + assert.Equal(t, maxmagnitude[0], allocable) + + // Slash testAddr + privateKeyHex := testutils.ANVIL_FIRST_PRIVATE_KEY + + chainWriter, err := testclients.NewTestChainWriterFromConfig(anvilHttpEndpoint, privateKeyHex, config) + require.NoError(t, err) + + waitForReceipt := true + delay := uint32(1) + receipt, err := chainWriter.SetAllocationDelay(context.Background(), operatorAddr, delay, waitForReceipt) + require.NoError(t, err) + require.Equal(t, gethtypes.ReceiptStatusSuccessful, receipt.Status) + + allocationConfigurationDelay := 1200 + testutils.AdvanceChainByNBlocksExecInContainer(context.Background(), allocationConfigurationDelay+1, anvilC) + + // Retrieve the allocation delay so that the delay is applied + _, err = chainReader.GetAllocationDelay(context.Background(), operatorAddr) + require.NoError(t, err) + + err = createOperatorSet(anvilHttpEndpoint, privateKeyHex, testAddr, operatorSetId, strategyAddr) + require.NoError(t, err) + + operatorSet := allocationmanager.OperatorSet{ + Avs: testAddr, + Id: operatorSetId, + } + slash_ammount := uint64(100) + allocateParams := []allocationmanager.IAllocationManagerTypesAllocateParams{ + { + OperatorSet: operatorSet, + Strategies: []common.Address{strategyAddr}, + NewMagnitudes: []uint64{slash_ammount}, + }, + } + + receipt, err = chainWriter.ModifyAllocations(context.Background(), operatorAddr, allocateParams, waitForReceipt) + require.NoError(t, err) + require.Equal(t, gethtypes.ReceiptStatusSuccessful, receipt.Status) + + // Assert that after slashing, Allocatable Magnitude + slash ammount equals Max allocatable magnitude + allocable, err = chainReader.GetAllocatableMagnitude(ctx, testAddr, strategyAddr) + assert.NoError(t, err) + + assert.Equal(t, maxmagnitude[0], allocable+slash_ammount) +} + func TestAdminFunctions(t *testing.T) { testConfig := testutils.GetDefaultTestConfig() anvilC, err := testutils.StartAnvilContainer(testConfig.AnvilStateFileName) From 56cd67421580f26afcc2d6534132079c41d08b59 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Wed, 15 Jan 2025 15:27:21 -0300 Subject: [PATCH 08/21] Improve GetOperatorShares test --- chainio/clients/elcontracts/reader_test.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index 51a1aa5d..c49ba762 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -143,7 +143,6 @@ func TestChainReader(t *testing.T) { }) t.Run("GetOperatorShares", func(t *testing.T) { - // Maybe could add more strategies strategyAddr := contractAddrs.Erc20MockStrategy strategies := []common.Address{strategyAddr} shares, err := clients.ElChainReader.GetOperatorShares( @@ -152,7 +151,19 @@ func TestChainReader(t *testing.T) { strategies, ) assert.NoError(t, err) - assert.NotZero(t, shares) + assert.Len(t, shares, 1) + + // with n strategies, response's list length is n + strategies = []common.Address{strategyAddr, strategyAddr, strategyAddr} + shares, err = clients.ElChainReader.GetOperatorShares( + ctx, + common.HexToAddress(operator.Address), + strategies, + ) + assert.NoError(t, err) + assert.NotEmpty(t, shares, 3) + + // We could test modify the shares and verify the diff is the expected }) t.Run("GetOperatorsShares", func(t *testing.T) { From fb3bcb60d4103dc327261b7c38ee8fe6389bd2c6 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Wed, 15 Jan 2025 15:52:52 -0300 Subject: [PATCH 09/21] Improve GetOperatorsShares test --- chainio/clients/elcontracts/reader_test.go | 44 ++++++++++++++++------ 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index c49ba762..5371fa84 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -161,33 +161,55 @@ func TestChainReader(t *testing.T) { strategies, ) assert.NoError(t, err) - assert.NotEmpty(t, shares, 3) + assert.Len(t, shares, 3) // We could test modify the shares and verify the diff is the expected }) t.Run("GetOperatorsShares", func(t *testing.T) { - // Maybe could add more operators and strategies - operatorAddrs := []common.Address{common.HexToAddress(operator.Address)} + operatorAddr := common.HexToAddress(operator.Address) + operators := []common.Address{operatorAddr} strategyAddr := contractAddrs.Erc20MockStrategy strategies := []common.Address{strategyAddr} shares, err := clients.ElChainReader.GetOperatorsShares( ctx, - operatorAddrs, + operators, strategies, ) assert.NoError(t, err) - assert.NotZero(t, shares) - }) + assert.Len(t, shares, 1) - t.Run("GetOperatorSetsForOperator", func(t *testing.T) { - // GetOperatorSetsForOperator with an operator without sets returns an empty list - operatorSet, err := clients.ElChainReader.GetOperatorSetsForOperator( + // with n strategies, response's list length is [1][n] + mult_strategies := []common.Address{strategyAddr, strategyAddr, strategyAddr} + shares, err = clients.ElChainReader.GetOperatorsShares( ctx, - common.HexToAddress(operator.Address), + operators, + mult_strategies, + ) + assert.NoError(t, err) + assert.Len(t, shares, 1) + assert.Len(t, shares[0], 3) + + // with n strategies, response's list length is [n][1] + mult_operators := []common.Address{operatorAddr, operatorAddr, operatorAddr} + shares, err = clients.ElChainReader.GetOperatorsShares( + ctx, + mult_operators, + strategies, + ) + assert.NoError(t, err) + assert.Len(t, shares, 3) + assert.Len(t, shares[0], 1) + + // with n strategies and n operators, response's list length is [n][n] + shares, err = clients.ElChainReader.GetOperatorsShares( + ctx, + mult_operators, + mult_strategies, ) assert.NoError(t, err) - assert.Empty(t, operatorSet) + assert.Len(t, shares, 3) + assert.Len(t, shares[2], 3) }) } From 448abaf8f5bb914e176df2a372d8c18b5925993b Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Wed, 15 Jan 2025 17:31:46 -0300 Subject: [PATCH 10/21] Modify terminology in TestGetAllocatableMagnitudeAndGetMaxMagnitudes --- chainio/clients/elcontracts/reader_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index 5371fa84..679ce76c 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -534,7 +534,7 @@ func TestGetAllocatableMagnitudeAndGetMaxMagnitudes(t *testing.T) { assert.Equal(t, maxmagnitude[0], allocable) - // Slash testAddr + // Reduce allocatable magnitude for testAddr privateKeyHex := testutils.ANVIL_FIRST_PRIVATE_KEY chainWriter, err := testclients.NewTestChainWriterFromConfig(anvilHttpEndpoint, privateKeyHex, config) @@ -549,7 +549,7 @@ func TestGetAllocatableMagnitudeAndGetMaxMagnitudes(t *testing.T) { allocationConfigurationDelay := 1200 testutils.AdvanceChainByNBlocksExecInContainer(context.Background(), allocationConfigurationDelay+1, anvilC) - // Retrieve the allocation delay so that the delay is applied + // Check that Allocation delay has been applied _, err = chainReader.GetAllocationDelay(context.Background(), operatorAddr) require.NoError(t, err) @@ -560,12 +560,12 @@ func TestGetAllocatableMagnitudeAndGetMaxMagnitudes(t *testing.T) { Avs: testAddr, Id: operatorSetId, } - slash_ammount := uint64(100) + allocatable_reduction := uint64(100) allocateParams := []allocationmanager.IAllocationManagerTypesAllocateParams{ { OperatorSet: operatorSet, Strategies: []common.Address{strategyAddr}, - NewMagnitudes: []uint64{slash_ammount}, + NewMagnitudes: []uint64{allocatable_reduction}, }, } @@ -577,7 +577,7 @@ func TestGetAllocatableMagnitudeAndGetMaxMagnitudes(t *testing.T) { allocable, err = chainReader.GetAllocatableMagnitude(ctx, testAddr, strategyAddr) assert.NoError(t, err) - assert.Equal(t, maxmagnitude[0], allocable+slash_ammount) + assert.Equal(t, maxmagnitude[0], allocable+allocatable_reduction) } func TestAdminFunctions(t *testing.T) { From 3389c126720c4b23fc68c630f340ecd98368bbed Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 15 Jan 2025 18:50:06 -0300 Subject: [PATCH 11/21] InstrumentedClient having rpcCallsCollector as mandatory (#378) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: tomasarrachea Co-authored-by: Tomás Grüner <47506558+MegaRedHand@users.noreply.github.com> --- chainio/clients/elcontracts/writer_test.go | 4 +++- chainio/clients/eth/instrumented_client.go | 9 ++++++--- metrics/collectors/rpc_calls/rpc_calls.go | 5 +++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/chainio/clients/elcontracts/writer_test.go b/chainio/clients/elcontracts/writer_test.go index 7c368de4..747d0aab 100644 --- a/chainio/clients/elcontracts/writer_test.go +++ b/chainio/clients/elcontracts/writer_test.go @@ -5,6 +5,7 @@ import ( "math/big" "os" "testing" + "time" "github.com/Layr-Labs/eigensdk-go/chainio/clients" "github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts" @@ -57,7 +58,7 @@ func TestRegisterOperator(t *testing.T) { context.Background(), []string{"cast", "send", - "0x408EfD9C90d59298A9b32F4441aC9Df6A2d8C3E1", + fundedAccount, "--value", "5ether", "--private-key", @@ -66,6 +67,7 @@ func TestRegisterOperator(t *testing.T) { ) assert.NoError(t, err) assert.Equal(t, 0, code) + time.Sleep(500 * time.Millisecond) // wait for the account to be funded ecdsaPrivateKey, err := crypto.HexToECDSA(fundedPrivateKeyHex) require.NoError(t, err) diff --git a/chainio/clients/eth/instrumented_client.go b/chainio/clients/eth/instrumented_client.go index 0e69347a..87dd3619 100644 --- a/chainio/clients/eth/instrumented_client.go +++ b/chainio/clients/eth/instrumented_client.go @@ -21,7 +21,7 @@ import ( // see https://github.com/ethereum/go-ethereum/issues/28267 type InstrumentedClient struct { client *ethclient.Client - rpcCallsCollector *rpccalls.Collector + rpcCallsCollector rpccalls.CollectorInterface // we store both client and version because that's what the web3_clientVersion jsonrpc call returns // https://ethereum.org/en/developers/docs/apis/json-rpc/#web3_clientversion clientAndVersion string @@ -30,7 +30,10 @@ type InstrumentedClient struct { var _ HttpBackend = (*InstrumentedClient)(nil) var _ WsBackend = (*InstrumentedClient)(nil) -func NewInstrumentedClient(rpcAddress string, rpcCallsCollector *rpccalls.Collector) (*InstrumentedClient, error) { +func NewInstrumentedClient( + rpcAddress string, + rpcCallsCollector rpccalls.CollectorInterface, +) (*InstrumentedClient, error) { client, err := ethclient.Dial(rpcAddress) if err != nil { return nil, err @@ -41,7 +44,7 @@ func NewInstrumentedClient(rpcAddress string, rpcCallsCollector *rpccalls.Collec func NewInstrumentedClientFromClient( client *ethclient.Client, - rpcCallsCollector *rpccalls.Collector, + rpcCallsCollector rpccalls.CollectorInterface, ) *InstrumentedClient { clientAndVersion := getClientAndVersion(client) return &InstrumentedClient{ diff --git a/metrics/collectors/rpc_calls/rpc_calls.go b/metrics/collectors/rpc_calls/rpc_calls.go index bd6e994b..f263f331 100644 --- a/metrics/collectors/rpc_calls/rpc_calls.go +++ b/metrics/collectors/rpc_calls/rpc_calls.go @@ -6,6 +6,11 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" ) +type CollectorInterface interface { + ObserveRPCRequestDurationSeconds(duration float64, method, clientVersion string) + AddRPCRequestTotal(method, clientVersion string) +} + // Collector contains instrumented metrics that should be incremented by the avs node using the methods below // it is used by the eigensdk's instrumented_client, but can also be used by avs teams to instrument their own client // if it differs from ours. From 0671041199986ed384b7982d8dbab07c3fb9225f Mon Sep 17 00:00:00 2001 From: Tomas Date: Wed, 15 Jan 2025 19:15:26 -0300 Subject: [PATCH 12/21] Remove outdated TODO (#396) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Pablo Deymonnaz Co-authored-by: Tomás Grüner <47506558+MegaRedHand@users.noreply.github.com> --- services/bls_aggregation/blsagg.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/services/bls_aggregation/blsagg.go b/services/bls_aggregation/blsagg.go index 90bf5ff6..4c22d1e8 100644 --- a/services/bls_aggregation/blsagg.go +++ b/services/bls_aggregation/blsagg.go @@ -605,11 +605,6 @@ func (a *BlsAggregatorService) closeTaskGoroutine(taskIndex types.TaskIndex) { // verifySignature verifies that a signature is valid against the operator pubkey stored in the // operatorsAvsStateDict for that particular task -// TODO(samlaf): right now we are only checking that the *digest* is signed correctly!! -// we could be sent a signature of any kind of garbage and we would happily aggregate it -// this forces the avs code to verify that the digest is indeed the digest of a valid taskResponse -// we could take taskResponse as an interface{} and have avs code pass us a taskResponseHashFunction -// that we could use to hash and verify the taskResponse itself func (a *BlsAggregatorService) verifySignature( taskIndex types.TaskIndex, signedTaskResponseDigest types.SignedTaskResponseDigest, From 1e176a1a1c2bdb04e903fe25a918b23d24fa1a5c Mon Sep 17 00:00:00 2001 From: Mateo Rico <89949621+ricomateo@users.noreply.github.com> Date: Thu, 16 Jan 2025 12:12:14 -0300 Subject: [PATCH 13/21] test: `elcontracts.ChainWriter` claim functions (slashing) (#436) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomás Grüner <47506558+MegaRedHand@users.noreply.github.com> --- Makefile | 4 +- chainio/clients/elcontracts/writer.go | 8 +- chainio/clients/elcontracts/writer_test.go | 244 +++++- contracts/bindings/MockERC20/binding.go | 883 +++++++++++++++++++++ 4 files changed, 1132 insertions(+), 7 deletions(-) create mode 100644 contracts/bindings/MockERC20/binding.go diff --git a/Makefile b/Makefile index e4df31e2..e36cf383 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ mocks: ## generates mocks .PHONY: tests tests: ## runs all tests - go test -race ./... -timeout=3m + go test -race ./... -timeout=4m .PHONY: tests-cover tests-cover: ## run all tests with test coverge @@ -67,7 +67,7 @@ middleware_default := "RegistryCoordinator IndexRegistry OperatorStateRetriever middleware_location := "./lib/eigenlayer-middleware" middleware_bindings_location := "../../bindings" -sdk_default := "MockAvsServiceManager ContractsRegistry" +sdk_default := "MockAvsServiceManager ContractsRegistry MockERC20" sdk_location := "." sdk_bindings_location := "./bindings" diff --git a/chainio/clients/elcontracts/writer.go b/chainio/clients/elcontracts/writer.go index 6b91f1fd..654bc394 100644 --- a/chainio/clients/elcontracts/writer.go +++ b/chainio/clients/elcontracts/writer.go @@ -342,7 +342,7 @@ func (w *ChainWriter) SetClaimerFor( func (w *ChainWriter) ProcessClaim( ctx context.Context, claim rewardscoordinator.IRewardsCoordinatorTypesRewardsMerkleClaim, - earnerAddress gethcommon.Address, + recipientAddress gethcommon.Address, waitForReceipt bool, ) (*gethtypes.Receipt, error) { if w.rewardsCoordinator == nil { @@ -354,7 +354,7 @@ func (w *ChainWriter) ProcessClaim( return nil, utils.WrapError("failed to get no send tx opts", err) } - tx, err := w.rewardsCoordinator.ProcessClaim(noSendTxOpts, claim, earnerAddress) + tx, err := w.rewardsCoordinator.ProcessClaim(noSendTxOpts, claim, recipientAddress) if err != nil { return nil, utils.WrapError("failed to create ProcessClaim tx", err) } @@ -424,7 +424,7 @@ func (w *ChainWriter) SetOperatorPISplit( func (w *ChainWriter) ProcessClaims( ctx context.Context, claims []rewardscoordinator.IRewardsCoordinatorTypesRewardsMerkleClaim, - earnerAddress gethcommon.Address, + recipientAddress gethcommon.Address, waitForReceipt bool, ) (*gethtypes.Receipt, error) { if w.rewardsCoordinator == nil { @@ -440,7 +440,7 @@ func (w *ChainWriter) ProcessClaims( return nil, utils.WrapError("failed to get no send tx opts", err) } - tx, err := w.rewardsCoordinator.ProcessClaims(noSendTxOpts, claims, earnerAddress) + tx, err := w.rewardsCoordinator.ProcessClaims(noSendTxOpts, claims, recipientAddress) if err != nil { return nil, utils.WrapError("failed to create ProcessClaims tx", err) } diff --git a/chainio/clients/elcontracts/writer_test.go b/chainio/clients/elcontracts/writer_test.go index 747d0aab..99de3fab 100644 --- a/chainio/clients/elcontracts/writer_test.go +++ b/chainio/clients/elcontracts/writer_test.go @@ -10,14 +10,16 @@ import ( "github.com/Layr-Labs/eigensdk-go/chainio/clients" "github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts" allocationmanager "github.com/Layr-Labs/eigensdk-go/contracts/bindings/AllocationManager" - rewardscoordinator "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IRewardsCoordinator" + strategy "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IStrategy" + mockerc20 "github.com/Layr-Labs/eigensdk-go/contracts/bindings/MockERC20" regcoord "github.com/Layr-Labs/eigensdk-go/contracts/bindings/RegistryCoordinator" "github.com/Layr-Labs/eigensdk-go/logging" "github.com/Layr-Labs/eigensdk-go/testutils" "github.com/Layr-Labs/eigensdk-go/testutils/testclients" "github.com/Layr-Labs/eigensdk-go/types" "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" @@ -663,6 +665,246 @@ func TestRemoveAdmin(t *testing.T) { }) } +// Returns a (test) claim for the given cumulativeEarnings, whose earner is +// the account given by the testutils.ANVIL_FIRST_ADDRESS address. +// This was taken from the eigensdk-rs +// https://github.com/Layr-Labs/eigensdk-rs/blob/d79b3672584b92f3c5fb204fde6bea394fbf0f12/crates/chainio/clients/elcontracts/src/lib.rs#L146 +func newTestClaim( + chainReader *elcontracts.ChainReader, + httpEndpoint string, + cumulativeEarnings int64, + privateKeyHex string, +) (*rewardscoordinator.IRewardsCoordinatorTypesRewardsMerkleClaim, error) { + contractAddrs := testutils.GetContractAddressesFromContractRegistry(httpEndpoint) + mockStrategyAddr := contractAddrs.Erc20MockStrategy + rewardsCoordinatorAddr := contractAddrs.RewardsCoordinator + waitForReceipt := true + + ethClient, err := ethclient.Dial(httpEndpoint) + if err != nil { + return nil, utils.WrapError("Failed to create eth client", err) + } + + txManager, err := testclients.NewTestTxManager(httpEndpoint, privateKeyHex) + if err != nil { + return nil, utils.WrapError("Failed to create tx manager", err) + } + + contractStrategy, err := strategy.NewContractIStrategy(mockStrategyAddr, ethClient) + if err != nil { + return nil, utils.WrapError("Failed to fetch strategy contract", err) + } + + tokenAddr, err := contractStrategy.UnderlyingToken(&bind.CallOpts{Context: context.Background()}) + if err != nil { + return nil, utils.WrapError("Failed to fetch token address", err) + } + + token, err := mockerc20.NewContractMockERC20(tokenAddr, ethClient) + if err != nil { + return nil, utils.WrapError("Failed to create token contract", err) + } + + noSendTxOpts, err := txManager.GetNoSendTxOpts() + if err != nil { + return nil, utils.WrapError("Failed to get NoSend tx opts", err) + } + + // Mint tokens for the RewardsCoordinator + tx, err := token.Mint(noSendTxOpts, rewardsCoordinatorAddr, big.NewInt(cumulativeEarnings)) + if err != nil { + return nil, utils.WrapError("Failed to create Mint tx", err) + } + + _, err = txManager.Send(context.Background(), tx, waitForReceipt) + if err != nil { + return nil, utils.WrapError("Failed to mint tokens for RewardsCoordinator", err) + } + + // 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(testutils.ANVIL_FIRST_ADDRESS) + tokenLeaf := rewardscoordinator.IRewardsCoordinatorTypesTokenTreeMerkleLeaf{ + Token: tokenAddr, + CumulativeEarnings: big.NewInt(cumulativeEarnings), + } + 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[:]...) + + // Hash token tree leaf to get root + earnerTokenRoot := crypto.Keccak256(encodedTokenLeaf) + + // Generate earner tree leaf + earnerLeaf := rewardscoordinator.IRewardsCoordinatorTypesEarnerTreeMerkleLeaf{ + Earner: earnerAddr, + EarnerTokenRoot: [32]byte(earnerTokenRoot), + } + // Encode earner leaft + encodedEarnerLeaf := []byte{} + earnerLeafSalt := uint8(0) + encodedEarnerLeaf = append(encodedEarnerLeaf, earnerLeafSalt) + encodedEarnerLeaf = append(encodedEarnerLeaf, earnerLeaf.Earner.Bytes()...) + encodedEarnerLeaf = append(encodedEarnerLeaf, earnerTokenRoot...) + + // Hash encoded 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 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 := [32]byte(earnerTreeRoot) + // Fetch the current timestamp to increase it + currRewardsCalculationEndTimestamp, err := chainReader.CurrRewardsCalculationEndTimestamp(context.Background()) + if err != nil { + return nil, utils.WrapError("Failed to call CurrRewardsCalculationEndTimestamp", err) + } + + rewardsCoordinator, err := rewardscoordinator.NewContractIRewardsCoordinator(rewardsCoordinatorAddr, ethClient) + if err != nil { + return nil, utils.WrapError("Failed to create rewards coordinator contract", err) + } + + rewardsUpdater := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS) + + // Change the rewards updater to be able to submit the new root + tx, err = rewardsCoordinator.SetRewardsUpdater(noSendTxOpts, rewardsUpdater) + if err != nil { + return nil, utils.WrapError("Failed to create SetRewardsUpdater tx", err) + } + + _, err = txManager.Send(context.Background(), tx, waitForReceipt) + if err != nil { + return nil, utils.WrapError("Failed to setRewardsUpdate", err) + } + + tx, err = rewardsCoordinator.SubmitRoot(noSendTxOpts, root, currRewardsCalculationEndTimestamp+1) + if err != nil { + return nil, utils.WrapError("Failed to create SubmitRoot tx", err) + } + + _, err = txManager.Send(context.Background(), tx, waitForReceipt) + if err != nil { + return nil, utils.WrapError("Failed to submit root", err) + } + + return &claim, nil +} + +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 := testutils.ANVIL_FIRST_PRIVATE_KEY + contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) + + rewardsCoordinatorAddr := contractAddrs.RewardsCoordinator + config := elcontracts.Config{ + DelegationManagerAddress: contractAddrs.DelegationManager, + RewardsCoordinatorAddress: rewardsCoordinatorAddr, + } + + // Create ChainWriter + chainWriter, err := testclients.NewTestChainWriterFromConfig(anvilHttpEndpoint, privateKeyHex, config) + require.NoError(t, err) + + chainReader, err := testclients.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.Equal(t, gethtypes.ReceiptStatusSuccessful, receipt.Status) + + waitForReceipt := true + cumulativeEarnings := int64(42) + recipient := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS) + claim, err := newTestClaim(chainReader, anvilHttpEndpoint, cumulativeEarnings, privateKeyHex) + require.NoError(t, err) + + receipt, err = chainWriter.ProcessClaim(context.Background(), *claim, recipient, waitForReceipt) + require.NoError(t, err) + require.Equal(t, gethtypes.ReceiptStatusSuccessful, receipt.Status) +} + +func TestProcessClaims(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 := testutils.ANVIL_FIRST_PRIVATE_KEY + contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) + + rewardsCoordinatorAddr := contractAddrs.RewardsCoordinator + config := elcontracts.Config{ + DelegationManagerAddress: contractAddrs.DelegationManager, + RewardsCoordinatorAddress: rewardsCoordinatorAddr, + } + + // Create ChainWriter + chainWriter, err := testclients.NewTestChainWriterFromConfig(anvilHttpEndpoint, privateKeyHex, config) + require.NoError(t, err) + + chainReader, err := testclients.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.Equal(t, gethtypes.ReceiptStatusSuccessful, receipt.Status) + + recipient := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS) + + waitForReceipt := true + cumulativeEarnings1 := int64(42) + cumulativeEarnings2 := int64(4256) + + // Generate 2 claims + claim1, err := newTestClaim(chainReader, anvilHttpEndpoint, cumulativeEarnings1, privateKeyHex) + require.NoError(t, err) + + claim2, err := newTestClaim(chainReader, anvilHttpEndpoint, cumulativeEarnings2, privateKeyHex) + require.NoError(t, err) + claims := []rewardscoordinator.IRewardsCoordinatorTypesRewardsMerkleClaim{ + *claim1, *claim2, + } + receipt, err = chainWriter.ProcessClaims(context.Background(), claims, recipient, waitForReceipt) + require.NoError(t, err) + require.Equal(t, gethtypes.ReceiptStatusSuccessful, receipt.Status) +} + // Creates an operator set with `avsAddress`, `operatorSetId` and `erc20MockStrategyAddr`. func createOperatorSet( anvilHttpEndpoint string, diff --git a/contracts/bindings/MockERC20/binding.go b/contracts/bindings/MockERC20/binding.go new file mode 100644 index 00000000..de7fc24b --- /dev/null +++ b/contracts/bindings/MockERC20/binding.go @@ -0,0 +1,883 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contractMockERC20 + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// ContractMockERC20MetaData contains all meta data concerning the ContractMockERC20 contract. +var ContractMockERC20MetaData = &bind.MetaData{ + ABI: "[{\"type\":\"function\",\"name\":\"allowance\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"approve\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"balanceOf\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decimals\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decreaseAllowance\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"subtractedValue\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"increaseAllowance\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"addedValue\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"mint\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"name\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"symbol\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalSupply\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transfer\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Approval\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false}]", + Bin: "0x60806040523461031357604080519081016001600160401b03811182821017610226576040908152600a82526926b7b1b5902a37b5b2b760b11b602083015280519081016001600160401b038111828210176102265760405260038152624d434b60e81b602082015281516001600160401b03811161022657600354600181811c91168015610309575b602082101461020857601f81116102a6575b50602092601f821160011461024557928192935f9261023a575b50508160011b915f199060031b1c1916176003555b80516001600160401b03811161022657600454600181811c9116801561021c575b602082101461020857601f81116101a5575b50602091601f8211600114610145579181925f9261013a575b50508160011b915f199060031b1c1916176004555b6040516108b490816103188239f35b015190505f80610116565b601f1982169260045f52805f20915f5b85811061018d57508360019510610175575b505050811b0160045561012b565b01515f1960f88460031b161c191690555f8080610167565b91926020600181928685015181550194019201610155565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c810191602084106101fe575b601f0160051c01905b8181106101f357506100fd565b5f81556001016101e6565b90915081906101dd565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100eb565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100b5565b601f1982169360035f52805f20915f5b86811061028e5750836001959610610276575b505050811b016003556100ca565b01515f1960f88460031b161c191690555f8080610268565b91926020600181928685015181550194019201610255565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c810191602084106102ff575b601f0160051c01905b8181106102f4575061009b565b5f81556001016102e7565b90915081906102de565b90607f1690610089565b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146104b757508063095ea7b31461049157806318160ddd1461047457806323b872dd14610447578063313ce5671461042c57806339509351146103de57806340c10f191461031a57806370a08231146102e357806395d89b41146101c8578063a457c2d714610125578063a9059cbb146100f45763dd62ed3e146100a0575f80fd5b346100f05760403660031901126100f0576100b96105b0565b6100c16105c6565b6001600160a01b039182165f908152600160209081526040808320949093168252928352819020549051908152f35b5f80fd5b346100f05760403660031901126100f05761011a6101106105b0565b6024359033610701565b602060405160018152f35b346100f05760403660031901126100f05761013e6105b0565b60243590335f52600160205260405f2060018060a01b0382165f5260205260405f2054918083106101755761011a920390336105fd565b60405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608490fd5b346100f0575f3660031901126100f0576040515f6004548060011c906001811680156102d9575b6020831081146102c5578285529081156102a95750600114610254575b50819003601f01601f191681019067ffffffffffffffff8211818310176102405761023c82918260405282610586565b0390f35b634e487b7160e01b5f52604160045260245ffd5b905060045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5f905b8282106102935750602091508201018261020c565b600181602092548385880101520191019061027e565b90506020925060ff191682840152151560051b8201018261020c565b634e487b7160e01b5f52602260045260245ffd5b91607f16916101ef565b346100f05760203660031901126100f0576001600160a01b036103046105b0565b165f525f602052602060405f2054604051908152f35b346100f05760403660031901126100f0576103336105b0565b6001600160a01b03166024358115610399577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6020826103765f946002546105dc565b6002558484528382526040842061038e8282546105dc565b9055604051908152a3005b60405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606490fd5b346100f05760403660031901126100f05761011a6103fa6105b0565b335f52600160205260405f2060018060a01b0382165f5260205261042560405f2060243590546105dc565b90336105fd565b346100f0575f3660031901126100f057602060405160128152f35b346100f05760603660031901126100f05761011a6104636105b0565b61046b6105c6565b60443591610701565b346100f0575f3660031901126100f0576020600254604051908152f35b346100f05760403660031901126100f05761011a6104ad6105b0565b60243590336105fd565b346100f0575f3660031901126100f0575f6003548060011c9060018116801561057c575b6020831081146102c5578285529081156102a957506001146105275750819003601f01601f191681019067ffffffffffffffff8211818310176102405761023c82918260405282610586565b905060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5f905b8282106105665750602091508201018261020c565b6001816020925483858801015201910190610551565b91607f16916104db565b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b03821682036100f057565b602435906001600160a01b03821682036100f057565b919082018092116105e957565b634e487b7160e01b5f52601160045260245ffd5b6001600160a01b03169081156106b0576001600160a01b03169182156106605760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591835f526001825260405f20855f5282528060405f2055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b6001600160a01b031690811561082b576001600160a01b03169182156107da57815f525f60205260405f205481811061078657817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f2061077b8282546105dc565b9055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fdfea2646970667358221220a7860fd1be9ff583c7b2a726a88033e14c79dc553b5d796305055b3464b2d7fe64736f6c634300081b0033", +} + +// ContractMockERC20ABI is the input ABI used to generate the binding from. +// Deprecated: Use ContractMockERC20MetaData.ABI instead. +var ContractMockERC20ABI = ContractMockERC20MetaData.ABI + +// ContractMockERC20Bin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use ContractMockERC20MetaData.Bin instead. +var ContractMockERC20Bin = ContractMockERC20MetaData.Bin + +// DeployContractMockERC20 deploys a new Ethereum contract, binding an instance of ContractMockERC20 to it. +func DeployContractMockERC20(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *ContractMockERC20, error) { + parsed, err := ContractMockERC20MetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ContractMockERC20Bin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &ContractMockERC20{ContractMockERC20Caller: ContractMockERC20Caller{contract: contract}, ContractMockERC20Transactor: ContractMockERC20Transactor{contract: contract}, ContractMockERC20Filterer: ContractMockERC20Filterer{contract: contract}}, nil +} + +// ContractMockERC20Methods is an auto generated interface around an Ethereum contract. +type ContractMockERC20Methods interface { + ContractMockERC20Calls + ContractMockERC20Transacts + ContractMockERC20Filters +} + +// ContractMockERC20Calls is an auto generated interface that defines the call methods available for an Ethereum contract. +type ContractMockERC20Calls interface { + Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) + + BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) + + Decimals(opts *bind.CallOpts) (uint8, error) + + Name(opts *bind.CallOpts) (string, error) + + Symbol(opts *bind.CallOpts) (string, error) + + TotalSupply(opts *bind.CallOpts) (*big.Int, error) +} + +// ContractMockERC20Transacts is an auto generated interface that defines the transact methods available for an Ethereum contract. +type ContractMockERC20Transacts interface { + Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) + + DecreaseAllowance(opts *bind.TransactOpts, spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) + + IncreaseAllowance(opts *bind.TransactOpts, spender common.Address, addedValue *big.Int) (*types.Transaction, error) + + Mint(opts *bind.TransactOpts, account common.Address, amount *big.Int) (*types.Transaction, error) + + Transfer(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) + + TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) +} + +// ContractMockERC20Filterer is an auto generated interface that defines the log filtering methods available for an Ethereum contract. +type ContractMockERC20Filters interface { + FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*ContractMockERC20ApprovalIterator, error) + WatchApproval(opts *bind.WatchOpts, sink chan<- *ContractMockERC20Approval, owner []common.Address, spender []common.Address) (event.Subscription, error) + ParseApproval(log types.Log) (*ContractMockERC20Approval, error) + + FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ContractMockERC20TransferIterator, error) + WatchTransfer(opts *bind.WatchOpts, sink chan<- *ContractMockERC20Transfer, from []common.Address, to []common.Address) (event.Subscription, error) + ParseTransfer(log types.Log) (*ContractMockERC20Transfer, error) +} + +// ContractMockERC20 is an auto generated Go binding around an Ethereum contract. +type ContractMockERC20 struct { + ContractMockERC20Caller // Read-only binding to the contract + ContractMockERC20Transactor // Write-only binding to the contract + ContractMockERC20Filterer // Log filterer for contract events +} + +// ContractMockERC20 implements the ContractMockERC20Methods interface. +var _ ContractMockERC20Methods = (*ContractMockERC20)(nil) + +// ContractMockERC20Caller is an auto generated read-only Go binding around an Ethereum contract. +type ContractMockERC20Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContractMockERC20Caller implements the ContractMockERC20Calls interface. +var _ ContractMockERC20Calls = (*ContractMockERC20Caller)(nil) + +// ContractMockERC20Transactor is an auto generated write-only Go binding around an Ethereum contract. +type ContractMockERC20Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContractMockERC20Transactor implements the ContractMockERC20Transacts interface. +var _ ContractMockERC20Transacts = (*ContractMockERC20Transactor)(nil) + +// ContractMockERC20Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ContractMockERC20Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContractMockERC20Filterer implements the ContractMockERC20Filters interface. +var _ ContractMockERC20Filters = (*ContractMockERC20Filterer)(nil) + +// ContractMockERC20Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ContractMockERC20Session struct { + Contract *ContractMockERC20 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ContractMockERC20CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ContractMockERC20CallerSession struct { + Contract *ContractMockERC20Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ContractMockERC20TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ContractMockERC20TransactorSession struct { + Contract *ContractMockERC20Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ContractMockERC20Raw is an auto generated low-level Go binding around an Ethereum contract. +type ContractMockERC20Raw struct { + Contract *ContractMockERC20 // Generic contract binding to access the raw methods on +} + +// ContractMockERC20CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ContractMockERC20CallerRaw struct { + Contract *ContractMockERC20Caller // Generic read-only contract binding to access the raw methods on +} + +// ContractMockERC20TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ContractMockERC20TransactorRaw struct { + Contract *ContractMockERC20Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewContractMockERC20 creates a new instance of ContractMockERC20, bound to a specific deployed contract. +func NewContractMockERC20(address common.Address, backend bind.ContractBackend) (*ContractMockERC20, error) { + contract, err := bindContractMockERC20(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ContractMockERC20{ContractMockERC20Caller: ContractMockERC20Caller{contract: contract}, ContractMockERC20Transactor: ContractMockERC20Transactor{contract: contract}, ContractMockERC20Filterer: ContractMockERC20Filterer{contract: contract}}, nil +} + +// NewContractMockERC20Caller creates a new read-only instance of ContractMockERC20, bound to a specific deployed contract. +func NewContractMockERC20Caller(address common.Address, caller bind.ContractCaller) (*ContractMockERC20Caller, error) { + contract, err := bindContractMockERC20(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ContractMockERC20Caller{contract: contract}, nil +} + +// NewContractMockERC20Transactor creates a new write-only instance of ContractMockERC20, bound to a specific deployed contract. +func NewContractMockERC20Transactor(address common.Address, transactor bind.ContractTransactor) (*ContractMockERC20Transactor, error) { + contract, err := bindContractMockERC20(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ContractMockERC20Transactor{contract: contract}, nil +} + +// NewContractMockERC20Filterer creates a new log filterer instance of ContractMockERC20, bound to a specific deployed contract. +func NewContractMockERC20Filterer(address common.Address, filterer bind.ContractFilterer) (*ContractMockERC20Filterer, error) { + contract, err := bindContractMockERC20(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ContractMockERC20Filterer{contract: contract}, nil +} + +// bindContractMockERC20 binds a generic wrapper to an already deployed contract. +func bindContractMockERC20(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ContractMockERC20MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ContractMockERC20 *ContractMockERC20Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ContractMockERC20.Contract.ContractMockERC20Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ContractMockERC20 *ContractMockERC20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ContractMockERC20.Contract.ContractMockERC20Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ContractMockERC20 *ContractMockERC20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ContractMockERC20.Contract.ContractMockERC20Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ContractMockERC20 *ContractMockERC20CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ContractMockERC20.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ContractMockERC20 *ContractMockERC20TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ContractMockERC20.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ContractMockERC20 *ContractMockERC20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ContractMockERC20.Contract.contract.Transact(opts, method, params...) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_ContractMockERC20 *ContractMockERC20Caller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { + var out []interface{} + err := _ContractMockERC20.contract.Call(opts, &out, "allowance", owner, spender) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_ContractMockERC20 *ContractMockERC20Session) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _ContractMockERC20.Contract.Allowance(&_ContractMockERC20.CallOpts, owner, spender) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_ContractMockERC20 *ContractMockERC20CallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _ContractMockERC20.Contract.Allowance(&_ContractMockERC20.CallOpts, owner, spender) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_ContractMockERC20 *ContractMockERC20Caller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { + var out []interface{} + err := _ContractMockERC20.contract.Call(opts, &out, "balanceOf", account) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_ContractMockERC20 *ContractMockERC20Session) BalanceOf(account common.Address) (*big.Int, error) { + return _ContractMockERC20.Contract.BalanceOf(&_ContractMockERC20.CallOpts, account) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_ContractMockERC20 *ContractMockERC20CallerSession) BalanceOf(account common.Address) (*big.Int, error) { + return _ContractMockERC20.Contract.BalanceOf(&_ContractMockERC20.CallOpts, account) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_ContractMockERC20 *ContractMockERC20Caller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _ContractMockERC20.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_ContractMockERC20 *ContractMockERC20Session) Decimals() (uint8, error) { + return _ContractMockERC20.Contract.Decimals(&_ContractMockERC20.CallOpts) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_ContractMockERC20 *ContractMockERC20CallerSession) Decimals() (uint8, error) { + return _ContractMockERC20.Contract.Decimals(&_ContractMockERC20.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_ContractMockERC20 *ContractMockERC20Caller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _ContractMockERC20.contract.Call(opts, &out, "name") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_ContractMockERC20 *ContractMockERC20Session) Name() (string, error) { + return _ContractMockERC20.Contract.Name(&_ContractMockERC20.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_ContractMockERC20 *ContractMockERC20CallerSession) Name() (string, error) { + return _ContractMockERC20.Contract.Name(&_ContractMockERC20.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_ContractMockERC20 *ContractMockERC20Caller) Symbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _ContractMockERC20.contract.Call(opts, &out, "symbol") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_ContractMockERC20 *ContractMockERC20Session) Symbol() (string, error) { + return _ContractMockERC20.Contract.Symbol(&_ContractMockERC20.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_ContractMockERC20 *ContractMockERC20CallerSession) Symbol() (string, error) { + return _ContractMockERC20.Contract.Symbol(&_ContractMockERC20.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_ContractMockERC20 *ContractMockERC20Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ContractMockERC20.contract.Call(opts, &out, "totalSupply") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_ContractMockERC20 *ContractMockERC20Session) TotalSupply() (*big.Int, error) { + return _ContractMockERC20.Contract.TotalSupply(&_ContractMockERC20.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_ContractMockERC20 *ContractMockERC20CallerSession) TotalSupply() (*big.Int, error) { + return _ContractMockERC20.Contract.TotalSupply(&_ContractMockERC20.CallOpts) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_ContractMockERC20 *ContractMockERC20Transactor) Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.contract.Transact(opts, "approve", spender, amount) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_ContractMockERC20 *ContractMockERC20Session) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.Approve(&_ContractMockERC20.TransactOpts, spender, amount) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_ContractMockERC20 *ContractMockERC20TransactorSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.Approve(&_ContractMockERC20.TransactOpts, spender, amount) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_ContractMockERC20 *ContractMockERC20Transactor) DecreaseAllowance(opts *bind.TransactOpts, spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.contract.Transact(opts, "decreaseAllowance", spender, subtractedValue) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_ContractMockERC20 *ContractMockERC20Session) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.DecreaseAllowance(&_ContractMockERC20.TransactOpts, spender, subtractedValue) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_ContractMockERC20 *ContractMockERC20TransactorSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.DecreaseAllowance(&_ContractMockERC20.TransactOpts, spender, subtractedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_ContractMockERC20 *ContractMockERC20Transactor) IncreaseAllowance(opts *bind.TransactOpts, spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.contract.Transact(opts, "increaseAllowance", spender, addedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_ContractMockERC20 *ContractMockERC20Session) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.IncreaseAllowance(&_ContractMockERC20.TransactOpts, spender, addedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_ContractMockERC20 *ContractMockERC20TransactorSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.IncreaseAllowance(&_ContractMockERC20.TransactOpts, spender, addedValue) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address account, uint256 amount) returns() +func (_ContractMockERC20 *ContractMockERC20Transactor) Mint(opts *bind.TransactOpts, account common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.contract.Transact(opts, "mint", account, amount) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address account, uint256 amount) returns() +func (_ContractMockERC20 *ContractMockERC20Session) Mint(account common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.Mint(&_ContractMockERC20.TransactOpts, account, amount) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address account, uint256 amount) returns() +func (_ContractMockERC20 *ContractMockERC20TransactorSession) Mint(account common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.Mint(&_ContractMockERC20.TransactOpts, account, amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_ContractMockERC20 *ContractMockERC20Transactor) Transfer(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.contract.Transact(opts, "transfer", to, amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_ContractMockERC20 *ContractMockERC20Session) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.Transfer(&_ContractMockERC20.TransactOpts, to, amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_ContractMockERC20 *ContractMockERC20TransactorSession) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.Transfer(&_ContractMockERC20.TransactOpts, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_ContractMockERC20 *ContractMockERC20Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.contract.Transact(opts, "transferFrom", from, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_ContractMockERC20 *ContractMockERC20Session) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.TransferFrom(&_ContractMockERC20.TransactOpts, from, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_ContractMockERC20 *ContractMockERC20TransactorSession) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _ContractMockERC20.Contract.TransferFrom(&_ContractMockERC20.TransactOpts, from, to, amount) +} + +// ContractMockERC20ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the ContractMockERC20 contract. +type ContractMockERC20ApprovalIterator struct { + Event *ContractMockERC20Approval // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ContractMockERC20ApprovalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ContractMockERC20Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ContractMockERC20Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ContractMockERC20ApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ContractMockERC20ApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ContractMockERC20Approval represents a Approval event raised by the ContractMockERC20 contract. +type ContractMockERC20Approval struct { + Owner common.Address + Spender common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_ContractMockERC20 *ContractMockERC20Filterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*ContractMockERC20ApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _ContractMockERC20.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return &ContractMockERC20ApprovalIterator{contract: _ContractMockERC20.contract, event: "Approval", logs: logs, sub: sub}, nil +} + +// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_ContractMockERC20 *ContractMockERC20Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *ContractMockERC20Approval, owner []common.Address, spender []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _ContractMockERC20.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ContractMockERC20Approval) + if err := _ContractMockERC20.contract.UnpackLog(event, "Approval", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_ContractMockERC20 *ContractMockERC20Filterer) ParseApproval(log types.Log) (*ContractMockERC20Approval, error) { + event := new(ContractMockERC20Approval) + if err := _ContractMockERC20.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ContractMockERC20TransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the ContractMockERC20 contract. +type ContractMockERC20TransferIterator struct { + Event *ContractMockERC20Transfer // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ContractMockERC20TransferIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ContractMockERC20Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ContractMockERC20Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ContractMockERC20TransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ContractMockERC20TransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ContractMockERC20Transfer represents a Transfer event raised by the ContractMockERC20 contract. +type ContractMockERC20Transfer struct { + From common.Address + To common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_ContractMockERC20 *ContractMockERC20Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ContractMockERC20TransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _ContractMockERC20.contract.FilterLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return &ContractMockERC20TransferIterator{contract: _ContractMockERC20.contract, event: "Transfer", logs: logs, sub: sub}, nil +} + +// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_ContractMockERC20 *ContractMockERC20Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *ContractMockERC20Transfer, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _ContractMockERC20.contract.WatchLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ContractMockERC20Transfer) + if err := _ContractMockERC20.contract.UnpackLog(event, "Transfer", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_ContractMockERC20 *ContractMockERC20Filterer) ParseTransfer(log types.Log) (*ContractMockERC20Transfer, error) { + event := new(ContractMockERC20Transfer) + if err := _ContractMockERC20.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} From 3bfa0a631871ee2d72bce73298cf75bff2c950b5 Mon Sep 17 00:00:00 2001 From: Maximo Palopoli <96491141+maximopalopoli@users.noreply.github.com> Date: Thu, 16 Jan 2025 12:15:24 -0300 Subject: [PATCH 14/21] test: use read clients builder (#441) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomás Grüner <47506558+MegaRedHand@users.noreply.github.com> --- chainio/clients/elcontracts/reader_test.go | 18 ++++++------ testutils/testclients/testclients.go | 33 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index c5a2ce07..cb9e26b4 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -18,7 +18,7 @@ import ( ) func TestChainReader(t *testing.T) { - clients, anvilHttpEndpoint := testclients.BuildTestClients(t) + read_clients, anvilHttpEndpoint := testclients.BuildTestReadClients(t) ctx := context.Background() contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) @@ -27,13 +27,13 @@ func TestChainReader(t *testing.T) { } t.Run("is operator registered", func(t *testing.T) { - isOperator, err := clients.ElChainReader.IsOperatorRegistered(ctx, operator) + isOperator, err := read_clients.ElChainReader.IsOperatorRegistered(ctx, operator) assert.NoError(t, err) assert.Equal(t, isOperator, true) }) t.Run("get operator details", func(t *testing.T) { - operatorDetails, err := clients.ElChainReader.GetOperatorDetails(ctx, operator) + operatorDetails, err := read_clients.ElChainReader.GetOperatorDetails(ctx, operator) assert.NoError(t, err) assert.NotNil(t, operatorDetails) assert.Equal(t, operator.Address, operatorDetails.Address) @@ -41,7 +41,7 @@ func TestChainReader(t *testing.T) { t.Run("get strategy and underlying token", func(t *testing.T) { strategyAddr := contractAddrs.Erc20MockStrategy - strategy, underlyingTokenAddr, err := clients.ElChainReader.GetStrategyAndUnderlyingToken( + strategy, underlyingTokenAddr, err := read_clients.ElChainReader.GetStrategyAndUnderlyingToken( ctx, strategyAddr, ) @@ -49,7 +49,7 @@ func TestChainReader(t *testing.T) { assert.NotNil(t, strategy) assert.NotEqual(t, common.Address{}, underlyingTokenAddr) - erc20Token, err := erc20.NewContractIERC20(underlyingTokenAddr, clients.EthHttpClient) + erc20Token, err := erc20.NewContractIERC20(underlyingTokenAddr, read_clients.EthHttpClient) assert.NoError(t, err) tokenName, err := erc20Token.Name(&bind.CallOpts{}) @@ -59,7 +59,7 @@ func TestChainReader(t *testing.T) { t.Run("get strategy and underlying ERC20 token", func(t *testing.T) { strategyAddr := contractAddrs.Erc20MockStrategy - strategy, contractUnderlyingToken, underlyingTokenAddr, err := clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( + strategy, contractUnderlyingToken, underlyingTokenAddr, err := read_clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( ctx, strategyAddr, ) @@ -74,7 +74,7 @@ func TestChainReader(t *testing.T) { }) t.Run("get operator shares in strategy", func(t *testing.T) { - shares, err := clients.ElChainReader.GetOperatorSharesInStrategy( + shares, err := read_clients.ElChainReader.GetOperatorSharesInStrategy( ctx, common.HexToAddress(operator.Address), contractAddrs.Erc20MockStrategy, @@ -88,7 +88,7 @@ func TestChainReader(t *testing.T) { delegationApprover := common.Address{0x0} approverSalt := [32]byte{} expiry := big.NewInt(0) - digest, err := clients.ElChainReader.CalculateDelegationApprovalDigestHash( + digest, err := read_clients.ElChainReader.CalculateDelegationApprovalDigestHash( ctx, staker, common.HexToAddress(operator.Address), @@ -104,7 +104,7 @@ func TestChainReader(t *testing.T) { avs := common.Address{0x0} salt := [32]byte{} expiry := big.NewInt(0) - digest, err := clients.ElChainReader.CalculateOperatorAVSRegistrationDigestHash( + digest, err := read_clients.ElChainReader.CalculateOperatorAVSRegistrationDigestHash( ctx, common.HexToAddress(operator.Address), avs, diff --git a/testutils/testclients/testclients.go b/testutils/testclients/testclients.go index 02565998..91ac9f23 100644 --- a/testutils/testclients/testclients.go +++ b/testutils/testclients/testclients.go @@ -58,6 +58,39 @@ func BuildTestClients(t *testing.T) (*clients.Clients, string) { return clients, anvilHttpEndpoint } +// Starts an anvil container and builds the ChainIO ReadClients for read-only testing. +func BuildTestReadClients(t *testing.T) (*clients.ReadClients, string) { + testConfig := testutils.GetDefaultTestConfig() + anvilC, err := testutils.StartAnvilContainer(testConfig.AnvilStateFileName) + require.NoError(t, err) + + anvilHttpEndpoint, err := anvilC.Endpoint(context.Background(), "http") + require.NoError(t, err) + + anvilWsEndpoint, err := anvilC.Endpoint(context.Background(), "ws") + require.NoError(t, err) + logger := logging.NewTextSLogger(os.Stdout, &logging.SLoggerOptions{Level: testConfig.LogLevel}) + + contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) + require.NoError(t, err) + + chainioConfig := clients.BuildAllConfig{ + EthHttpUrl: anvilHttpEndpoint, + EthWsUrl: anvilWsEndpoint, + RegistryCoordinatorAddr: contractAddrs.RegistryCoordinator.String(), + OperatorStateRetrieverAddr: contractAddrs.OperatorStateRetriever.String(), + AvsName: "exampleAvs", + PromMetricsIpPortAddress: ":9090", + } + + clients, err := clients.BuildReadClients( + chainioConfig, + logger, + ) + require.NoError(t, err) + return clients, anvilHttpEndpoint +} + // Creates a testing ChainWriter from an httpEndpoint, private key and config. // This is needed because the existing testclients.BuildTestClients returns a // ChainReader with a null rewardsCoordinator, which is required for some of the tests. From fda56ad16fad8d29f63bf376dd9d7cf6f32f012e Mon Sep 17 00:00:00 2001 From: Maximo Palopoli <96491141+maximopalopoli@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:36:19 -0300 Subject: [PATCH 15/21] test: add reader test coverage (#429) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: ricomateo Co-authored-by: Tomás Grüner <47506558+MegaRedHand@users.noreply.github.com> --- chainio/clients/elcontracts/reader_test.go | 312 +++++++++++++++++++++ 1 file changed, 312 insertions(+) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index cb9e26b4..92d59164 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -7,12 +7,14 @@ import ( "github.com/Layr-Labs/eigensdk-go/chainio/clients/elcontracts" erc20 "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IERC20" + rewardscoordinator "github.com/Layr-Labs/eigensdk-go/contracts/bindings/IRewardsCoordinator" "github.com/Layr-Labs/eigensdk-go/testutils" "github.com/Layr-Labs/eigensdk-go/testutils/testclients" "github.com/Layr-Labs/eigensdk-go/types" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -114,6 +116,316 @@ func TestChainReader(t *testing.T) { assert.NoError(t, err) assert.NotEmpty(t, digest) }) + + t.Run("get staker shares", func(t *testing.T) { + strategies, shares, err := read_clients.ElChainReader.GetStakerShares( + ctx, + common.HexToAddress(operator.Address), + ) + 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) { + val := big.NewInt(0) + address, err := read_clients.ElChainReader.GetDelegatedOperator( + ctx, + common.HexToAddress(operator.Address), + val, + ) + + assert.NoError(t, err) + // The delegated operator of an operator is the operator itself + assert.Equal(t, address.String(), operator.Address) + }) + +} + +func TestGetCurrentClaimableDistributionRoot(t *testing.T) { + // Verifies GetCurrentClaimableDistributionRoot returns 0 if no root and the root if there's one + _, anvilHttpEndpoint := testclients.BuildTestClients(t) + ctx := context.Background() + + contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) + + root := [32]byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + } + + rewardsCoordinatorAddr := contractAddrs.RewardsCoordinator + config := elcontracts.Config{ + DelegationManagerAddress: contractAddrs.DelegationManager, + RewardsCoordinatorAddress: rewardsCoordinatorAddr, + } + + chainReader, err := testclients.NewTestChainReaderFromConfig(anvilHttpEndpoint, config) + require.NoError(t, err) + + // Create and configure rewards coordinator + ethClient, err := ethclient.Dial(anvilHttpEndpoint) + require.NoError(t, err) + rewardsCoordinator, err := rewardscoordinator.NewContractIRewardsCoordinator(rewardsCoordinatorAddr, ethClient) + require.NoError(t, err) + + ecdsaPrivKeyHex := testutils.ANVIL_FIRST_PRIVATE_KEY + + // Set delay to zero to inmediatly operate with coordinator + receipt, err := setTestRewardsCoordinatorActivationDelay(anvilHttpEndpoint, ecdsaPrivKeyHex, uint32(0)) + require.NoError(t, err) + require.Equal(t, receipt.Status, gethtypes.ReceiptStatusSuccessful) + + // Create txManager to send transactions to the Ethereum node + txManager, err := testclients.NewTestTxManager(anvilHttpEndpoint, ecdsaPrivKeyHex) + require.NoError(t, err) + noSendTxOpts, err := txManager.GetNoSendTxOpts() + require.NoError(t, err) + + rewardsUpdater := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS) + + // Change the rewards updater to be able to submit the new root + tx, err := rewardsCoordinator.SetRewardsUpdater(noSendTxOpts, rewardsUpdater) + require.NoError(t, err) + + waitForReceipt := true + _, err = txManager.Send(context.Background(), tx, waitForReceipt) + require.NoError(t, err) + + // Check that if there is no root submitted the result is zero + distr_root, err := chainReader.GetCurrentClaimableDistributionRoot( + ctx, + ) + assert.NoError(t, err) + assert.Zero(t, distr_root.Root) + + currRewardsCalculationEndTimestamp, err := chainReader.CurrRewardsCalculationEndTimestamp(context.Background()) + require.NoError(t, err) + + tx, err = rewardsCoordinator.SubmitRoot(noSendTxOpts, root, currRewardsCalculationEndTimestamp+1) + require.NoError(t, err) + + _, err = txManager.Send(context.Background(), tx, waitForReceipt) + require.NoError(t, err) + + // Check that if there is a root submitted the result is that root + distr_root, err = chainReader.GetCurrentClaimableDistributionRoot( + ctx, + ) + assert.NoError(t, err) + assert.Equal(t, distr_root.Root, root) +} + +func TestGetRootIndexFromRootHash(t *testing.T) { + _, anvilHttpEndpoint := testclients.BuildTestClients(t) + ctx := context.Background() + + contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) + + rewardsCoordinatorAddr := contractAddrs.RewardsCoordinator + config := elcontracts.Config{ + DelegationManagerAddress: contractAddrs.DelegationManager, + RewardsCoordinatorAddress: rewardsCoordinatorAddr, + } + + chainReader, err := testclients.NewTestChainReaderFromConfig(anvilHttpEndpoint, config) + require.NoError(t, err) + + // Create and configure rewards coordinator + ethClient, err := ethclient.Dial(anvilHttpEndpoint) + require.NoError(t, err) + rewardsCoordinator, err := rewardscoordinator.NewContractIRewardsCoordinator(rewardsCoordinatorAddr, ethClient) + require.NoError(t, err) + ecdsaPrivKeyHex := testutils.ANVIL_FIRST_PRIVATE_KEY + + // Set delay to zero to inmediatly operate with coordinator + receipt, err := setTestRewardsCoordinatorActivationDelay(anvilHttpEndpoint, ecdsaPrivKeyHex, uint32(0)) + require.NoError(t, err) + require.Equal(t, receipt.Status, gethtypes.ReceiptStatusSuccessful) + + // Create txManager to send transactions to the Ethereum node + txManager, err := testclients.NewTestTxManager(anvilHttpEndpoint, ecdsaPrivKeyHex) + require.NoError(t, err) + noSendTxOpts, err := txManager.GetNoSendTxOpts() + require.NoError(t, err) + + rewardsUpdater := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS) + + // Change the rewards updater to be able to submit the new root + tx, err := rewardsCoordinator.SetRewardsUpdater(noSendTxOpts, rewardsUpdater) + require.NoError(t, err) + + waitForReceipt := true + _, err = txManager.Send(context.Background(), tx, waitForReceipt) + require.NoError(t, err) + + root := [32]byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + } + + // Check that if there is no root submitted the result is an InvalidRoot error + root_index, err := chainReader.GetRootIndexFromHash( + ctx, + root, + ) + assert.Error(t, err) + assert.Equal(t, err.Error(), "execution reverted: custom error 0x504570e3", + "GetRootIndexFromHash should return an InvalidRoot() error", + ) + assert.Zero(t, root_index) + + currRewardsCalculationEndTimestamp, err := chainReader.CurrRewardsCalculationEndTimestamp(context.Background()) + require.NoError(t, err) + + tx, err = rewardsCoordinator.SubmitRoot(noSendTxOpts, root, currRewardsCalculationEndTimestamp+1) + require.NoError(t, err) + + _, err = txManager.Send(context.Background(), tx, waitForReceipt) + require.NoError(t, err) + + root2 := [32]byte{ + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + } + + currRewardsCalculationEndTimestamp2, err := chainReader.CurrRewardsCalculationEndTimestamp(context.Background()) + require.NoError(t, err) + + tx, err = rewardsCoordinator.SubmitRoot(noSendTxOpts, root2, currRewardsCalculationEndTimestamp2+1) + require.NoError(t, err) + + _, err = txManager.Send(context.Background(), tx, waitForReceipt) + require.NoError(t, err) + + // Check that the first root inserted is the first indexed (zero) + root_index, err = chainReader.GetRootIndexFromHash( + ctx, + root, + ) + assert.NoError(t, err) + assert.Equal(t, root_index, uint32(0)) + + // Check that the second root inserted is the second indexed (zero) + root_index, err = chainReader.GetRootIndexFromHash( + ctx, + root2, + ) + assert.NoError(t, err) + assert.Equal(t, root_index, uint32(1)) +} + +func TestGetCumulativeClaimedRewards(t *testing.T) { + clients, anvilHttpEndpoint := testclients.BuildTestClients(t) + ctx := context.Background() + + contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) + + rewardsCoordinatorAddr := contractAddrs.RewardsCoordinator + config := elcontracts.Config{ + DelegationManagerAddress: contractAddrs.DelegationManager, + RewardsCoordinatorAddress: rewardsCoordinatorAddr, + } + privateKeyHex := testutils.ANVIL_FIRST_PRIVATE_KEY + + // Create ChainWriter + chainWriter, err := testclients.NewTestChainWriterFromConfig(anvilHttpEndpoint, privateKeyHex, config) + require.NoError(t, err) + + chainReader, err := testclients.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 == gethtypes.ReceiptStatusSuccessful) + + strategyAddr := contractAddrs.Erc20MockStrategy + strategy, contractUnderlyingToken, underlyingTokenAddr, err := clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( + ctx, + strategyAddr, + ) + assert.NoError(t, err) + assert.NotNil(t, strategy) + assert.NotEqual(t, common.Address{}, underlyingTokenAddr) + assert.NotNil(t, contractUnderlyingToken) + + anvil_address := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS) + + // This tests that without claims result is zero + claimed, err := chainReader.GetCumulativeClaimed(ctx, anvil_address, underlyingTokenAddr) + assert.Zero(t, claimed.Cmp(big.NewInt(0))) + assert.NoError(t, err) + + cumulativeEarnings := int64(45) + claim, err := newTestClaim(chainReader, anvilHttpEndpoint, cumulativeEarnings, privateKeyHex) + require.NoError(t, err) + + receipt, err = chainWriter.ProcessClaim(context.Background(), *claim, rewardsCoordinatorAddr, true) + require.NoError(t, err) + require.True(t, receipt.Status == gethtypes.ReceiptStatusSuccessful) + + // This tests that with a claim result is cumulativeEarnings + claimed, err = chainReader.GetCumulativeClaimed(ctx, anvil_address, underlyingTokenAddr) + assert.Equal(t, claimed, big.NewInt(cumulativeEarnings)) + assert.NoError(t, err) +} + +func TestCheckClaim(t *testing.T) { + clients, anvilHttpEndpoint := testclients.BuildTestClients(t) + ctx := context.Background() + + contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) + + rewardsCoordinatorAddr := contractAddrs.RewardsCoordinator + config := elcontracts.Config{ + DelegationManagerAddress: contractAddrs.DelegationManager, + RewardsCoordinatorAddress: rewardsCoordinatorAddr, + } + privateKeyHex := testutils.ANVIL_FIRST_PRIVATE_KEY + + // Create ChainWriter and chain reader + chainWriter, err := testclients.NewTestChainWriterFromConfig(anvilHttpEndpoint, privateKeyHex, config) + require.NoError(t, err) + + chainReader, err := testclients.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 == gethtypes.ReceiptStatusSuccessful) + + cumulativeEarnings := int64(45) + claim, err := newTestClaim(chainReader, anvilHttpEndpoint, cumulativeEarnings, privateKeyHex) + require.NoError(t, err) + + receipt, err = chainWriter.ProcessClaim(context.Background(), *claim, rewardsCoordinatorAddr, true) + require.NoError(t, err) + require.True(t, receipt.Status == gethtypes.ReceiptStatusSuccessful) + + strategyAddr := contractAddrs.Erc20MockStrategy + strategy, contractUnderlyingToken, underlyingTokenAddr, err := clients.ElChainReader.GetStrategyAndUnderlyingERC20Token( + ctx, + strategyAddr, + ) + assert.NoError(t, err) + assert.NotNil(t, strategy) + assert.NotEqual(t, common.Address{}, underlyingTokenAddr) + assert.NotNil(t, contractUnderlyingToken) + + checked, err := chainReader.CheckClaim(ctx, *claim) + require.NoError(t, err) + assert.True(t, checked) } func TestAdminFunctions(t *testing.T) { From 40e57eeb5693e395d33c39f97af278e1cfccfde5 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Thu, 16 Jan 2025 15:40:27 -0300 Subject: [PATCH 16/21] Remove constant --- testutils/anvil.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/testutils/anvil.go b/testutils/anvil.go index 58c4d7b7..ffdace4d 100644 --- a/testutils/anvil.go +++ b/testutils/anvil.go @@ -27,8 +27,6 @@ const ( ANVIL_THIRD_ADDRESS = "3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" ) -const REWARDS_COORDINATOR_ADDRESS = "2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" - // This address is hardcoded because it is required by the elcontracts tests but is not // registered in the ContractRegistry in the contracts-deployed-anvil-state.json anvil state. const PERMISSION_CONTROLLER_ADDRESS = "610178dA211FEF7D417bC0e6FeD39F05609AD788" From 563216e9216e1051877e784be5864180401c67e6 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Thu, 16 Jan 2025 15:40:45 -0300 Subject: [PATCH 17/21] Add comment in GetOperatorsShares --- chainio/clients/elcontracts/reader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainio/clients/elcontracts/reader.go b/chainio/clients/elcontracts/reader.go index fdc608e3..00e6b5a6 100644 --- a/chainio/clients/elcontracts/reader.go +++ b/chainio/clients/elcontracts/reader.go @@ -461,7 +461,7 @@ func (r *ChainReader) GetOperatorShares( func (r *ChainReader) GetOperatorsShares( ctx context.Context, - operatorAddress []gethcommon.Address, + operatorAddress []gethcommon.Address, // Shouldn't be named operatorAddresses? strategyAddresses []gethcommon.Address, ) ([][]*big.Int, error) { if r.delegationManager == nil { From 35d85056bf2b4fcdf0f2fda8cf2648aaab856bde Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Thu, 16 Jan 2025 16:39:43 -0300 Subject: [PATCH 18/21] Rename GetOperatorsShares parameter to plural --- chainio/clients/elcontracts/reader.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chainio/clients/elcontracts/reader.go b/chainio/clients/elcontracts/reader.go index 00e6b5a6..c4e12ba7 100644 --- a/chainio/clients/elcontracts/reader.go +++ b/chainio/clients/elcontracts/reader.go @@ -461,13 +461,13 @@ func (r *ChainReader) GetOperatorShares( func (r *ChainReader) GetOperatorsShares( ctx context.Context, - operatorAddress []gethcommon.Address, // Shouldn't be named operatorAddresses? + operatorAddresses []gethcommon.Address, strategyAddresses []gethcommon.Address, ) ([][]*big.Int, error) { if r.delegationManager == nil { return nil, errors.New("DelegationManager contract not provided") } - return r.delegationManager.GetOperatorsShares(&bind.CallOpts{Context: ctx}, operatorAddress, strategyAddresses) + return r.delegationManager.GetOperatorsShares(&bind.CallOpts{Context: ctx}, operatorAddresses, strategyAddresses) } // GetNumOperatorSetsForOperator returns the number of operator sets that an operator is part of From 16753b14e52c7eba84e24029512694514c619b43 Mon Sep 17 00:00:00 2001 From: Maximo Palopoli <96491141+maximopalopoli@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:47:48 -0300 Subject: [PATCH 19/21] fix: change literal string values for constants or predefined values (#442) --- chainio/clients/avsregistry/writer_test.go | 6 +++--- chainio/clients/elcontracts/reader_test.go | 2 +- chainio/clients/elcontracts/writer_test.go | 3 +-- chainio/clients/eth/instrumented_client_test.go | 3 +-- chainio/clients/wallet/privatekey_wallet_test.go | 3 +-- chainio/txmgr/geometric/geometric_example_test.go | 2 +- chainio/txmgr/geometric/geometric_test.go | 2 +- services/bls_aggregation/blsagg_test.go | 3 +-- signerv2/signer_test.go | 5 ++--- testutils/anvil.go | 2 +- testutils/testclients/testclients.go | 2 +- 11 files changed, 14 insertions(+), 19 deletions(-) diff --git a/chainio/clients/avsregistry/writer_test.go b/chainio/clients/avsregistry/writer_test.go index 11537dc5..ed775962 100644 --- a/chainio/clients/avsregistry/writer_test.go +++ b/chainio/clients/avsregistry/writer_test.go @@ -6,6 +6,7 @@ import ( chainioutils "github.com/Layr-Labs/eigensdk-go/chainio/utils" "github.com/Layr-Labs/eigensdk-go/crypto/bls" + "github.com/Layr-Labs/eigensdk-go/testutils" "github.com/Layr-Labs/eigensdk-go/testutils/testclients" "github.com/Layr-Labs/eigensdk-go/types" gethcommon "github.com/ethereum/go-ethereum/common" @@ -20,9 +21,8 @@ func TestWriterMethods(t *testing.T) { keypair, err := bls.NewKeyPairFromString("0x01") require.NoError(t, err) - addr := gethcommon.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266") - ecdsaPrivKeyHex := "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - ecdsaPrivateKey, err := crypto.HexToECDSA(ecdsaPrivKeyHex) + addr := gethcommon.HexToAddress(testutils.ANVIL_FIRST_ADDRESS) + ecdsaPrivateKey, err := crypto.HexToECDSA(testutils.ANVIL_FIRST_PRIVATE_KEY) require.NoError(t, err) quorumNumbers := types.QuorumNums{0} diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index 92d59164..1a24f602 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -25,7 +25,7 @@ func TestChainReader(t *testing.T) { contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint) operator := types.Operator{ - Address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + Address: testutils.ANVIL_FIRST_ADDRESS, } t.Run("is operator registered", func(t *testing.T) { diff --git a/chainio/clients/elcontracts/writer_test.go b/chainio/clients/elcontracts/writer_test.go index 99de3fab..1e95d1c0 100644 --- a/chainio/clients/elcontracts/writer_test.go +++ b/chainio/clients/elcontracts/writer_test.go @@ -187,8 +187,7 @@ func TestSetClaimerFor(t *testing.T) { require.NoError(t, err) waitForReceipt := true - claimer := common.HexToAddress("0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6") - + claimer := contractAddrs.RewardsCoordinator // call SetClaimerFor receipt, err := chainWriter.SetClaimerFor(context.Background(), claimer, waitForReceipt) require.NoError(t, err) diff --git a/chainio/clients/eth/instrumented_client_test.go b/chainio/clients/eth/instrumented_client_test.go index 6566856e..f22d7480 100644 --- a/chainio/clients/eth/instrumented_client_test.go +++ b/chainio/clients/eth/instrumented_client_test.go @@ -362,8 +362,7 @@ func TestTransactionMethods(t *testing.T) { Gas: 21000, }) - ecdsaPrivKeyHex := "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - ecdsaPrivKey, err := crypto.HexToECDSA(ecdsaPrivKeyHex) + ecdsaPrivKey, err := crypto.HexToECDSA(testutils.ANVIL_FIRST_PRIVATE_KEY) assert.NoError(t, err) signer := types.LatestSignerForChainID(big.NewInt(31337)) signature, err := crypto.Sign(signer.Hash(tx).Bytes(), ecdsaPrivKey) diff --git a/chainio/clients/wallet/privatekey_wallet_test.go b/chainio/clients/wallet/privatekey_wallet_test.go index 1cb1a9ce..a48e7385 100644 --- a/chainio/clients/wallet/privatekey_wallet_test.go +++ b/chainio/clients/wallet/privatekey_wallet_test.go @@ -31,8 +31,7 @@ func TestPrivateKeyWallet(t *testing.T) { ethClient, err := ethclient.Dial(anvilHttpEndpoint) require.NoError(t, err) - ecdsaPrivKeyHex := "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - ecdsaPrivKey, err := crypto.HexToECDSA(ecdsaPrivKeyHex) + ecdsaPrivKey, err := crypto.HexToECDSA(testutils.ANVIL_FIRST_PRIVATE_KEY) require.NoError(t, err) signerV2, signerAddr, err := signerv2.SignerFromConfig(signerv2.Config{PrivateKey: ecdsaPrivKey}, chainId) if err != nil { diff --git a/chainio/txmgr/geometric/geometric_example_test.go b/chainio/txmgr/geometric/geometric_example_test.go index d77740a9..e6820be2 100644 --- a/chainio/txmgr/geometric/geometric_example_test.go +++ b/chainio/txmgr/geometric/geometric_example_test.go @@ -33,7 +33,7 @@ func ExampleGeometricTxManager() { panic(err) } - ecdsaPrivateKey, err := crypto.HexToECDSA("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") + ecdsaPrivateKey, err := crypto.HexToECDSA(testutils.ANVIL_FIRST_PRIVATE_KEY) if err != nil { panic(err) } diff --git a/chainio/txmgr/geometric/geometric_test.go b/chainio/txmgr/geometric/geometric_test.go index 01c62bc0..a9d0095d 100644 --- a/chainio/txmgr/geometric/geometric_test.go +++ b/chainio/txmgr/geometric/geometric_test.go @@ -377,7 +377,7 @@ func newIntegrationTestHarness(t *testing.T) *integrationTestHarness { require.NoError(t, err) ecdsaSk, ecdsaAddr, err := ecdsa.KeyAndAddressFromHexKey( - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + testutils.ANVIL_FIRST_PRIVATE_KEY, ) require.NoError(t, err) diff --git a/services/bls_aggregation/blsagg_test.go b/services/bls_aggregation/blsagg_test.go index 72d5b0f2..5e3d0425 100644 --- a/services/bls_aggregation/blsagg_test.go +++ b/services/bls_aggregation/blsagg_test.go @@ -1644,8 +1644,7 @@ func TestIntegrationBlsAgg(t *testing.T) { testData := testutils.NewTestData(defaultInput) // define operator ecdsa and bls private keys - ecdsaPrivKeyHex := "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - ecdsaPrivKey, err := crypto.HexToECDSA(ecdsaPrivKeyHex) + ecdsaPrivKey, err := crypto.HexToECDSA(testutils.ANVIL_FIRST_PRIVATE_KEY) require.NoError(t, err) blsPrivKeyHex := testData.Input.BlsPrivKey blsKeyPair := newBlsKeyPairPanics(blsPrivKeyHex) diff --git a/signerv2/signer_test.go b/signerv2/signer_test.go index 7b6f7cae..8ccd2a05 100644 --- a/signerv2/signer_test.go +++ b/signerv2/signer_test.go @@ -14,8 +14,7 @@ import ( ) func TestPrivateKeySignerFn(t *testing.T) { - privateKeyHex := "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - privateKey, err := crypto.HexToECDSA(privateKeyHex) + privateKey, err := crypto.HexToECDSA(testutils.ANVIL_FIRST_PRIVATE_KEY) require.NoError(t, err) chainID := big.NewInt(1) @@ -74,7 +73,7 @@ func TestWeb3SignerFn(t *testing.T) { signer, err := signerv2.Web3SignerFn(anvilHttpEndpoint) require.NoError(t, err) - privateKey, err := crypto.HexToECDSA("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") + privateKey, err := crypto.HexToECDSA(testutils.ANVIL_FIRST_PRIVATE_KEY) require.NoError(t, err) anvilChainID := big.NewInt(31337) address := crypto.PubkeyToAddress(privateKey.PublicKey) diff --git a/testutils/anvil.go b/testutils/anvil.go index ffdace4d..4cda28c7 100644 --- a/testutils/anvil.go +++ b/testutils/anvil.go @@ -20,7 +20,7 @@ import ( ) const ( - ANVIL_FIRST_ADDRESS = "f39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + ANVIL_FIRST_ADDRESS = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ANVIL_FIRST_PRIVATE_KEY = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ANVIL_SECOND_ADDRESS = "70997970C51812dc3A010C7d01b50e0d17dc79C8" ANVIL_SECOND_PRIVATE_KEY = "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" diff --git a/testutils/testclients/testclients.go b/testutils/testclients/testclients.go index 91ac9f23..28e1b48e 100644 --- a/testutils/testclients/testclients.go +++ b/testutils/testclients/testclients.go @@ -33,7 +33,7 @@ func BuildTestClients(t *testing.T) (*clients.Clients, string) { require.NoError(t, err) logger := logging.NewTextSLogger(os.Stdout, &logging.SLoggerOptions{Level: testConfig.LogLevel}) - privateKeyHex := "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + privateKeyHex := testutils.ANVIL_FIRST_PRIVATE_KEY ecdsaPrivateKey, err := crypto.HexToECDSA(privateKeyHex) require.NoError(t, err) From 18e1163a23f5be5aa4f1f31252cbdd035ca7899c Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Thu, 16 Jan 2025 18:12:01 -0300 Subject: [PATCH 20/21] Rename maxmagnitude var to maxMagnitudes --- chainio/clients/elcontracts/reader_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index 1d191ea2..118567c1 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -525,14 +525,14 @@ func TestGetAllocatableMagnitudeAndGetMaxMagnitudes(t *testing.T) { operatorSetId := uint32(1) strategies := []common.Address{strategyAddr} - maxmagnitude, err := chainReader.GetMaxMagnitudes(ctx, testAddr, strategies) + maxMagnitudes, err := chainReader.GetMaxMagnitudes(ctx, testAddr, strategies) assert.NoError(t, err) // Assert that at the beginning, Allocatable Magnitude is Max allocatable magnitude allocable, err := chainReader.GetAllocatableMagnitude(ctx, testAddr, strategyAddr) assert.NoError(t, err) - assert.Equal(t, maxmagnitude[0], allocable) + assert.Equal(t, maxMagnitudes[0], allocable) // Reduce allocatable magnitude for testAddr privateKeyHex := testutils.ANVIL_FIRST_PRIVATE_KEY @@ -577,7 +577,7 @@ func TestGetAllocatableMagnitudeAndGetMaxMagnitudes(t *testing.T) { allocable, err = chainReader.GetAllocatableMagnitude(ctx, testAddr, strategyAddr) assert.NoError(t, err) - assert.Equal(t, maxmagnitude[0], allocable+allocatable_reduction) + assert.Equal(t, maxMagnitudes[0], allocable+allocatable_reduction) } func TestAdminFunctions(t *testing.T) { From d675c3f0e2e7bcf91e12ddd3d11184907df5cf76 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Thu, 16 Jan 2025 18:13:12 -0300 Subject: [PATCH 21/21] Improve comment terminology --- chainio/clients/elcontracts/reader_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainio/clients/elcontracts/reader_test.go b/chainio/clients/elcontracts/reader_test.go index 118567c1..13d8b9e3 100644 --- a/chainio/clients/elcontracts/reader_test.go +++ b/chainio/clients/elcontracts/reader_test.go @@ -573,7 +573,7 @@ func TestGetAllocatableMagnitudeAndGetMaxMagnitudes(t *testing.T) { require.NoError(t, err) require.Equal(t, gethtypes.ReceiptStatusSuccessful, receipt.Status) - // Assert that after slashing, Allocatable Magnitude + slash ammount equals Max allocatable magnitude + // Assert that after stake reduction, Allocatable Magnitude + reduction ammount equals Max allocatable magnitude allocable, err = chainReader.GetAllocatableMagnitude(ctx, testAddr, strategyAddr) assert.NoError(t, err)