From 925b333b83cb0d14aacbea7fc72a3b93fd304fc4 Mon Sep 17 00:00:00 2001 From: Madhur Shrimal Date: Wed, 28 Aug 2024 15:48:42 -0700 Subject: [PATCH] unsigned tx --- pkg/internal/common/contracts.go | 12 +++++ pkg/operator/allocations/initializedelay.go | 55 ++++++++++++++++++++- pkg/operator/allocations/update.go | 51 ++++++++++++++++++- pkg/rewards/claim.go | 6 +-- 4 files changed, 116 insertions(+), 8 deletions(-) diff --git a/pkg/internal/common/contracts.go b/pkg/internal/common/contracts.go index b6adf130..ff7fe70a 100644 --- a/pkg/internal/common/contracts.go +++ b/pkg/internal/common/contracts.go @@ -1,6 +1,7 @@ package common import ( + "context" "errors" "math/big" @@ -57,3 +58,14 @@ func GetELWriter( return eLWriter, nil } + +func IsSmartContractAddress(address gethcommon.Address, ethClient *ethclient.Client) bool { + code, err := ethClient.CodeAt(context.Background(), address, nil) + if err != nil { + // We return true here because we want to treat the address as a smart contract + // This is only used to gas estimation and creating unsigned transactions + // So it's fine if eth client return an error + return true + } + return len(code) > 0 +} diff --git a/pkg/operator/allocations/initializedelay.go b/pkg/operator/allocations/initializedelay.go index 5926398a..cfdbff52 100644 --- a/pkg/operator/allocations/initializedelay.go +++ b/pkg/operator/allocations/initializedelay.go @@ -54,6 +54,16 @@ func initializeDelayAction(cCtx *cli.Context, p utils.Prompter) error { config.avsDirectoryAddress = gethcommon.HexToAddress("0x8BffE5a668DB26bc5Ce8dC9C0096fB634747b62A") if config.broadcast { + confirm, err := p.Confirm( + "This will initialize the allocation delay for operator. You won't be able to set or change it again. Do you want to continue?", + ) + if err != nil { + return err + } + if !confirm { + logger.Info("Operation cancelled") + return nil + } eLWriter, err := common.GetELWriter( config.operatorAddress, config.signerConfig, @@ -76,8 +86,49 @@ func initializeDelayAction(cCtx *cli.Context, p utils.Prompter) error { } common.PrintTransactionInfo(receipt.TxHash.String(), config.chainID) } else { - logger.Infof("Operator Address: %s", config.operatorAddress.String()) - logger.Infof("Allocation Delay: %d", config.allocationDelay) + noSendTxOpts := common.GetNoSendTxOpts(config.operatorAddress) + _, _, contractBindings, err := elcontracts.BuildClients(elcontracts.Config{ + AvsDirectoryAddress: config.avsDirectoryAddress, + }, ethClient, nil, logger, nil) + if err != nil { + return err + } + // If operator is a smart contract, we can't estimate gas using geth + // since balance of contract can be 0, as it can be called by an EOA + // to claim. So we hardcode the gas limit to 150_000 so that we can + // create unsigned tx without gas limit estimation from contract bindings + if common.IsSmartContractAddress(config.operatorAddress, ethClient) { + // Claimer is a smart contract + noSendTxOpts.GasLimit = 150_000 + } + + unsignedTx, err := contractBindings.AvsDirectory.InitializeAllocationDelay(noSendTxOpts, config.allocationDelay) + if err != nil { + return eigenSdkUtils.WrapError("failed to create unsigned tx", err) + } + + if config.outputType == string(common.OutputType_Calldata) { + calldataHex := gethcommon.Bytes2Hex(unsignedTx.Data()) + if !common.IsEmptyString(config.output) { + err = common.WriteToFile([]byte(calldataHex), config.output) + if err != nil { + return err + } + logger.Infof("Call data written to file: %s", config.output) + } else { + fmt.Println(calldataHex) + } + } else { + if !common.IsEmptyString(config.output) { + fmt.Println("output file not supported for pretty output type") + fmt.Println() + } + fmt.Printf("Allocation delay %d will be set for operator %s\n", config.allocationDelay, config.operatorAddress.String()) + } + txFeeDetails := common.GetTxFeeDetails(unsignedTx) + fmt.Println() + txFeeDetails.Print() + fmt.Println("To broadcast the transaction, use the --broadcast flag") } return nil diff --git a/pkg/operator/allocations/update.go b/pkg/operator/allocations/update.go index c8868d53..439f4a8a 100644 --- a/pkg/operator/allocations/update.go +++ b/pkg/operator/allocations/update.go @@ -3,6 +3,7 @@ package allocations import ( "context" "errors" + "fmt" "math/big" "os" "sort" @@ -130,7 +131,55 @@ func updateAllocations(cCtx *cli.Context, p utils.Prompter) error { } common.PrintTransactionInfo(receipt.TxHash.String(), config.chainID) } else { - allocationsToUpdate.Print() + noSendTxOpts := common.GetNoSendTxOpts(config.operatorAddress) + _, _, contractBindings, err := elcontracts.BuildClients(elcontracts.Config{ + AvsDirectoryAddress: gethcommon.HexToAddress(avsDirectoryAddress), + }, ethClient, nil, logger, nil) + if err != nil { + return err + } + // If operator is a smart contract, we can't estimate gas using geth + // since balance of contract can be 0, as it can be called by an EOA + // to claim. So we hardcode the gas limit to 150_000 so that we can + // create unsigned tx without gas limit estimation from contract bindings + if common.IsSmartContractAddress(config.operatorAddress, ethClient) { + // Claimer is a smart contract + noSendTxOpts.GasLimit = 150_000 + } + + unsignedTx, err := contractBindings.AvsDirectory.ModifyAllocations( + noSendTxOpts, + config.operatorAddress, + allocationsToUpdate.allocations, + contractIAVSDirectory.ISignatureUtilsSignatureWithSaltAndExpiry{ + Expiry: big.NewInt(0), + }) + if err != nil { + return eigenSdkUtils.WrapError("failed to create unsigned tx", err) + } + + if config.outputType == string(common.OutputType_Calldata) { + calldataHex := gethcommon.Bytes2Hex(unsignedTx.Data()) + if !common.IsEmptyString(config.output) { + err = common.WriteToFile([]byte(calldataHex), config.output) + if err != nil { + return err + } + logger.Infof("Call data written to file: %s", config.output) + } else { + fmt.Println(calldataHex) + } + } else { + if !common.IsEmptyString(config.output) { + fmt.Println("output file not supported for pretty output type") + fmt.Println() + } + allocationsToUpdate.Print() + } + txFeeDetails := common.GetTxFeeDetails(unsignedTx) + fmt.Println() + txFeeDetails.Print() + fmt.Println("To broadcast the transaction, use the --broadcast flag") } return nil diff --git a/pkg/rewards/claim.go b/pkg/rewards/claim.go index 4c3e5415..006e8624 100644 --- a/pkg/rewards/claim.go +++ b/pkg/rewards/claim.go @@ -182,11 +182,7 @@ func Claim(cCtx *cli.Context, p utils.Prompter) error { // since balance of contract can be 0, as it can be called by an EOA // to claim. So we hardcode the gas limit to 150_000 so that we can // create unsigned tx without gas limit estimation from contract bindings - code, err := ethClient.CodeAt(ctx, config.ClaimerAddress, nil) - if err != nil { - return eigenSdkUtils.WrapError("failed to get code at address", err) - } - if len(code) > 0 { + if common.IsSmartContractAddress(config.ClaimerAddress, ethClient) { // Claimer is a smart contract noSendTxOpts.GasLimit = 150_000 }