From 0e6f3534c2c21a898179f21c28fc2aec1d2a5e26 Mon Sep 17 00:00:00 2001 From: Trajan0x Date: Sun, 7 Jan 2024 15:26:09 -0400 Subject: [PATCH] add custom evm-version to abigen for #1650 --- tools/abigen/cmd/commands.go | 43 ++++++++++++++++++++++++-- tools/abigen/internal/export_test.go | 4 +-- tools/abigen/internal/generate.go | 15 ++++++--- tools/abigen/internal/generate_test.go | 28 +++++++++++++++-- 4 files changed, 79 insertions(+), 11 deletions(-) diff --git a/tools/abigen/cmd/commands.go b/tools/abigen/cmd/commands.go index 9ae6f97274..f11a61d9c7 100644 --- a/tools/abigen/cmd/commands.go +++ b/tools/abigen/cmd/commands.go @@ -1,9 +1,12 @@ package cmd import ( + "fmt" "github.com/ethereum/go-ethereum/common" + "github.com/synapsecns/sanguine/core" "github.com/synapsecns/sanguine/tools/abigen/internal" "github.com/urfave/cli/v2" + "os" ) var solFlag = &cli.StringFlag{ @@ -31,12 +34,37 @@ var urlFlag = &cli.StringFlag{ Usage: "url of the etherscan api to use", } +var disableCI = &cli.BoolFlag{ + Name: "disable-ci", + Usage: "wether or not to disable regeneration on ci", +} + +var disableCIEtherscan = &cli.BoolFlag{ + Name: disableCI.Name, + Usage: "wether or not to disable regeneration on ci, this is disabled on etherscan by default because of api keys", + Value: true, +} + var optimizerRunsFlags = &cli.IntFlag{ Name: "optimizer-runs", Usage: "number of optimizations to run.", Value: 10000, } +var evmVersionFlags = &cli.StringFlag{ + Name: "evm-version", + Usage: "evm version to target", +} + +// strToPt converts a string to a pointer +// crucially, will return nil if stirng is empty +func strToPt(str string) *string { + if str == "" { + return nil + } + return core.PtrTo(str) +} + // GenerateCommand generates abi using flags. var GenerateCommand = &cli.Command{ Name: "generate", @@ -47,10 +75,16 @@ var GenerateCommand = &cli.Command{ filenameFlag, solVersionFlag, optimizerRunsFlags, + evmVersionFlags, + disableCI, }, Action: func(context *cli.Context) error { + if context.Bool(disableCI.Name) && os.Getenv("CI") != "" { + fmt.Print("skipping generation") + return nil + } //nolint: wrapcheck - return internal.BuildTemplates(context.String(solVersionFlag.Name), context.String(solFlag.Name), context.String(pkgFlag.Name), context.String(filenameFlag.Name), context.Int(optimizerRunsFlags.Name)) + return internal.BuildTemplates(context.String(solVersionFlag.Name), context.String(solFlag.Name), context.String(pkgFlag.Name), context.String(filenameFlag.Name), context.Int(optimizerRunsFlags.Name), strToPt(context.String(evmVersionFlags.Name))) }, } @@ -75,10 +109,15 @@ var EtherscanCommand = &cli.Command{ filenameFlag, solVersionFlag, urlFlag, + disableCIEtherscan, }, // TODO this needs to embed optimizations, etc from the real deployed contract. Action: func(context *cli.Context) error { + if context.Bool(disableCIEtherscan.Name) && os.Getenv("CI") != "" { + fmt.Print("skipping generation") + return nil + } //nolint: wrapcheck - return internal.GenerateABIFromEtherscan(context.Context, uint32(context.Int(chainIDFlag.Name)), context.String(urlFlag.Name), common.HexToAddress(context.String(addressFlag.Name)), context.String(filenameFlag.String()), context.String(solVersionFlag.Name), context.String(pkgFlag.Name)) + return internal.GenerateABIFromEtherscan(context.Context, uint32(context.Int(chainIDFlag.Name)), context.String(urlFlag.Name), common.HexToAddress(context.String(addressFlag.Name)), context.String(filenameFlag.Name), context.String(solVersionFlag.Name), context.String(pkgFlag.Name)) }, } diff --git a/tools/abigen/internal/export_test.go b/tools/abigen/internal/export_test.go index ce000c1c61..925914003b 100644 --- a/tools/abigen/internal/export_test.go +++ b/tools/abigen/internal/export_test.go @@ -11,8 +11,8 @@ func CreateRunFile(version string) (runFile *os.File, err error) { } // CompileSolidity exports compileSolidity for testingw. -func CompileSolidity(version string, filePath string, optimizeRuns int) (map[string]*compiler.Contract, error) { - return compileSolidity(version, filePath, optimizeRuns) +func CompileSolidity(version string, filePath string, optimizeRuns int, evmVersion *string) (map[string]*compiler.Contract, error) { + return compileSolidity(version, filePath, optimizeRuns, evmVersion) } // FilePathsAreEqual exports filePathsAreEqual for testing. diff --git a/tools/abigen/internal/generate.go b/tools/abigen/internal/generate.go index 1f5d715424..5c5141e7d8 100644 --- a/tools/abigen/internal/generate.go +++ b/tools/abigen/internal/generate.go @@ -32,7 +32,7 @@ func GenerateABIFromEtherscan(ctx context.Context, chainID uint32, url string, c return fmt.Errorf("could not get contract source for address %s: %w", contractAddress, err) } - solFile, err := os.CreateTemp("", fmt.Sprintf("%s.sol", path.Base(fileName))) + solFile, err := os.Create(fmt.Sprintf("%s/%s.sol", os.TempDir(), path.Base(fileName))) if err != nil { return fmt.Errorf("could not determine wd: %w", err) } @@ -51,13 +51,13 @@ func GenerateABIFromEtherscan(ctx context.Context, chainID uint32, url string, c optimizerRuns = contract.Runs } - return BuildTemplates(solVersion, solFile.Name(), pkgName, fileName, optimizerRuns) + return BuildTemplates(solVersion, solFile.Name(), pkgName, fileName, optimizerRuns, nil) } // BuildTemplates builds the templates. version is the solidity version to use and sol is the solidity file to use. -func BuildTemplates(version, file, pkg, filename string, optimizerRuns int) error { +func BuildTemplates(version, file, pkg, filename string, optimizerRuns int, evmVersion *string) error { // TODO ast - contracts, err := compileSolidity(version, file, optimizerRuns) + contracts, err := compileSolidity(version, file, optimizerRuns, evmVersion) if err != nil { return err } @@ -123,7 +123,7 @@ func BuildTemplates(version, file, pkg, filename string, optimizerRuns int) erro // compileSolidity uses docker to compile solidity. // nolint: cyclop -func compileSolidity(version string, filePath string, optimizeRuns int) (map[string]*compiler.Contract, error) { +func compileSolidity(version string, filePath string, optimizeRuns int, evmVersion *string) (map[string]*compiler.Contract, error) { runFile, err := createRunFile(version) if err != nil { return nil, err @@ -183,6 +183,11 @@ func compileSolidity(version string, filePath string, optimizeRuns int) (map[str // compile the solidity var stderr, stdout bytes.Buffer args := []string{"--combined-json", "bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes", "--optimize", "--optimize-runs", strconv.Itoa(optimizeRuns), "--allow-paths", "., ./, ../"} + + if evmVersion != nil { + args = append(args, fmt.Sprintf("--evm-version=%s", *evmVersion)) + } + //nolint: gosec cmd := exec.Command(runFile.Name(), append(args, "--", fmt.Sprintf("/solidity/%s", filepath.Base(solFile.Name())))...) cmd.Stderr = &stderr diff --git a/tools/abigen/internal/generate_test.go b/tools/abigen/internal/generate_test.go index c42fb82a07..123f987ba5 100644 --- a/tools/abigen/internal/generate_test.go +++ b/tools/abigen/internal/generate_test.go @@ -1,7 +1,10 @@ package internal_test import ( + "encoding/json" "errors" + "github.com/synapsecns/sanguine/core" + "github.com/synapsecns/sanguine/ethergo/debug" "os" "os/exec" "path/filepath" @@ -24,8 +27,8 @@ func TestCreateRunFile(t *testing.T) { } } -func (a *AbiSuite) TestCompileSolidity() { - vals, err := internal.CompileSolidity("0.8.4", a.exampleFilePath, 1) +func (a *AbiSuite) TestCompileSolidityImplicitEVM() { + vals, err := internal.CompileSolidity("0.8.4", a.exampleFilePath, 1, nil) Nil(a.T(), err) Len(a.T(), vals, 1) @@ -35,6 +38,27 @@ func (a *AbiSuite) TestCompileSolidity() { } } +func (a *AbiSuite) TestCompileSolidityExplicitEVM() { + // default would be shnghai + const testEvmVersion = "istanbul" + vals, err := internal.CompileSolidity("0.8.20", a.exampleFilePath, 1, core.PtrTo(testEvmVersion)) + Nil(a.T(), err) + + Len(a.T(), vals, 1) + for _, value := range vals { + Equal(a.T(), value.Info.CompilerVersion, "0.8.20") + Equal(a.T(), value.Info.LanguageVersion, "0.8.20") + + var metadata debug.ContractMetadata + err = json.Unmarshal([]byte(value.Info.Metadata), &metadata) + a.Require().NoError(err) + + if metadata.Settings.EvmVersion != testEvmVersion { + a.T().Errorf("expected %s to be %s", metadata.Language, testEvmVersion) + } + } +} + func TestFilePathsAreEqual(t *testing.T) { tests := []struct { file1 string