Commit 35f29894 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

op-bindings: remove bindgen (#10301)

Removes the bindgen cli tool from the repo since it is not owned
by anybody and also not used to generate bindings anymore since
we are moving away from auto generated bindings.
parent 9b630492
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
package bindgen
// The Init bytecode used for these tests can either be sourced
// on-chain using the deployment tx of these contracts, or can be
// found in the bindings output from BindGen (../bindings/)
var removeDeploymentSaltTests = []struct {
name string
deploymentData string
deploymentSalt string
expected string
}{
{
"Case #1",
Safe_v130InitBytecode,
"0000000000000000000000000000000000000000000000000000000000000000",
Safe_v130InitBytecodeNoSalt,
},
{
"Case #2",
Permit2InitBytecode,
"0000000000000000000000000000000000000000d3af2663da51c10215000000",
Permit2InitBytecodeNoSalt,
},
{
"Case #3",
EntryPointInitBytecode,
"0000000000000000000000000000000000000000000000000000000000000000",
EntryPointInitBytecodeNoSalt,
},
}
var removeDeploymentSaltTestsFailures = []struct {
name string
deploymentData string
deploymentSalt string
expectedError string
}{
{
"Failure Case #1 Invalid Regex",
"0x1234abc",
"[invalid-regex",
"failed to compile regular expression: error parsing regexp: missing closing ]: `[invalid-regex)`",
},
{
"Failure Case #2 Salt Not Found",
"0x1234abc",
"4567",
"expected salt: 4567 to be at the beginning of the contract initialization code: 0x1234abc, but it wasn't",
},
}
package bindgen
import (
"encoding/json"
"errors"
"fmt"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"github.com/ethereum-optimism/optimism/op-bindings/foundry"
)
type BindGenGeneratorLocal struct {
BindGenGeneratorBase
SourceMapsList string
ForgeArtifactsPath string
}
func (generator *BindGenGeneratorLocal) GenerateBindings() error {
contracts, err := readContractList(generator.Logger, generator.ContractsListPath)
if err != nil {
return fmt.Errorf("error reading contract list %s: %w", generator.ContractsListPath, err)
}
if len(contracts.Local) == 0 {
return fmt.Errorf("no contracts parsed from given contract list: %s", generator.ContractsListPath)
}
return generator.processContracts(contracts.Local)
}
func (generator *BindGenGeneratorLocal) processContracts(contracts []string) error {
tempArtifactsDir, err := mkTempArtifactsDir(generator.Logger)
if err != nil {
return err
}
defer func() {
err := os.RemoveAll(tempArtifactsDir)
if err != nil {
generator.Logger.Error("Error removing temporary artifact directory", "path", tempArtifactsDir, "err", err.Error())
} else {
generator.Logger.Debug("Successfully removed temporary artifact directory")
}
}()
sourceMapsList := strings.Split(generator.SourceMapsList, ",")
sourceMapsSet := make(map[string]struct{})
for _, k := range sourceMapsList {
sourceMapsSet[k] = struct{}{}
}
contractArtifactPaths, err := generator.getContractArtifactPaths()
if err != nil {
return err
}
for _, contractName := range contracts {
generator.Logger.Info("Generating bindings and metadata for local contract", "contract", contractName)
forgeArtifact, err := generator.readForgeArtifact(contractName, contractArtifactPaths)
if err != nil {
return err
}
abiFilePath, bytecodeFilePath, err := writeContractArtifacts(generator.Logger, tempArtifactsDir, contractName, forgeArtifact.Abi, []byte(forgeArtifact.Bytecode.Object.String()))
if err != nil {
return err
}
err = genContractBindings(generator.Logger, generator.MonorepoBasePath, abiFilePath, bytecodeFilePath, generator.BindingsPackageName, contractName)
if err != nil {
return err
}
}
return nil
}
func (generator *BindGenGeneratorLocal) getContractArtifactPaths() (map[string]string, error) {
// If some contracts have the same name then the path to their
// artifact depends on their full import path. Scan over all artifacts
// and hold a mapping from the contract name to the contract path.
// Walk walks the directory deterministically, so the earliest instance
// of the contract with the same name will be used
artifactPaths := make(map[string]string)
if err := filepath.Walk(generator.ForgeArtifactsPath,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if strings.HasSuffix(path, ".json") {
base := filepath.Base(path)
name := strings.TrimSuffix(base, ".json")
// remove the compiler version from the name
re := regexp.MustCompile(`\.\d+\.\d+\.\d+`)
sanitized := re.ReplaceAllString(name, "")
_, ok := artifactPaths[sanitized]
if !ok {
artifactPaths[sanitized] = path
} else {
generator.Logger.Warn("Multiple versions of forge artifacts exist, using lesser version", "contract", sanitized)
}
}
return nil
}); err != nil {
return artifactPaths, err
}
return artifactPaths, nil
}
func (generator *BindGenGeneratorLocal) readForgeArtifact(contractName string, contractArtifactPaths map[string]string) (foundry.Artifact, error) {
var forgeArtifact foundry.Artifact
contractArtifactPath := path.Join(generator.ForgeArtifactsPath, contractName+".sol", contractName+".json")
forgeArtifactRaw, err := os.ReadFile(contractArtifactPath)
if errors.Is(err, os.ErrNotExist) {
generator.Logger.Debug("Cannot find forge-artifact at standard path, trying provided path", "contract", contractName, "standardPath", contractArtifactPath, "providedPath", contractArtifactPaths[contractName])
contractArtifactPath = contractArtifactPaths[contractName]
forgeArtifactRaw, err = os.ReadFile(contractArtifactPath)
if errors.Is(err, os.ErrNotExist) {
return forgeArtifact, fmt.Errorf("cannot find forge-artifact of %q", contractName)
}
}
generator.Logger.Debug("Using forge-artifact", "path", contractArtifactPath)
if err := json.Unmarshal(forgeArtifactRaw, &forgeArtifact); err != nil {
return forgeArtifact, fmt.Errorf("failed to parse forge artifact of %q: %w", contractName, err)
}
return forgeArtifact, nil
}
package bindgen
import (
"context"
"fmt"
"os"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
type BindGenGeneratorRemote struct {
BindGenGeneratorBase
ContractDataClients struct {
Eth contractDataClient
Op contractDataClient
}
RpcClients struct {
Eth *ethclient.Client
Op *ethclient.Client
}
tempArtifactsDir string
}
type contractDataClient interface {
FetchAbi(ctx context.Context, address string) (string, error)
FetchDeployedBytecode(ctx context.Context, address string) (string, error)
FetchDeploymentTxHash(ctx context.Context, address string) (string, error)
FetchDeploymentTx(ctx context.Context, txHash string) (etherscan.Transaction, error)
}
type Deployments struct {
Eth common.Address `json:"eth"`
Op common.Address `json:"op"`
}
type RemoteContract struct {
Name string `json:"name"`
Verified bool `json:"verified"`
Deployments Deployments `json:"deployments"`
DeploymentSalt string `json:"deploymentSalt"`
Deployer common.Address `json:"deployer"`
ABI string `json:"abi"`
InitBytecode string `json:"initBytecode"`
}
type RemoteContractMetadata struct {
RemoteContract
Package string
InitBin string
DeployedBin string
}
func (generator *BindGenGeneratorRemote) GenerateBindings() error {
contracts, err := readContractList(generator.Logger, generator.ContractsListPath)
if err != nil {
return fmt.Errorf("error reading contract list %s: %w", generator.ContractsListPath, err)
}
if len(contracts.Remote) == 0 {
return fmt.Errorf("no contracts parsed from given contract list: %s", generator.ContractsListPath)
}
return generator.processContracts(contracts.Remote)
}
func (generator *BindGenGeneratorRemote) processContracts(contracts []RemoteContract) error {
var err error
generator.tempArtifactsDir, err = mkTempArtifactsDir(generator.Logger)
if err != nil {
return err
}
defer func() {
err := os.RemoveAll(generator.tempArtifactsDir)
if err != nil {
generator.Logger.Error("Error removing temporary artifact directory", "path", generator.tempArtifactsDir, "err", err.Error())
} else {
generator.Logger.Debug("Successfully removed temporary artifact directory")
}
}()
for _, contract := range contracts {
generator.Logger.Info("Generating bindings and metadata for remote contract", "contract", contract.Name)
contractMetadata := RemoteContractMetadata{
RemoteContract: RemoteContract{
Name: contract.Name,
Deployments: contract.Deployments,
DeploymentSalt: contract.DeploymentSalt,
ABI: contract.ABI,
Verified: contract.Verified,
},
Package: generator.BindingsPackageName,
}
var err error
switch contract.Name {
case "MultiCall3", "Safe_v130", "SafeL2_v130", "MultiSendCallOnly_v130",
"EntryPoint", "SafeSingletonFactory", "DeterministicDeploymentProxy":
err = generator.standardHandler(&contractMetadata)
case "Create2Deployer":
err = generator.create2DeployerHandler(&contractMetadata)
case "MultiSend_v130":
err = generator.multiSendHandler(&contractMetadata)
case "SenderCreator":
// The SenderCreator contract is deployed by EntryPoint, so the transaction data
// from the deployment transaction is for the entire EntryPoint deployment.
// So, we're manually providing the initialization bytecode
contractMetadata.InitBin = contract.InitBytecode
err = generator.senderCreatorHandler(&contractMetadata)
case "Permit2":
// Permit2 has an immutable Solidity variable that resolves to block.chainid,
// so we can't use the deployed bytecode, and instead must generate it
// at some later point not handled by BindGen.
// DeployerAddress is intended to be used to help deploy Permit2 at it's deterministic address
// to a chain set with the required id to be able to obtain a diff minimized deployed bytecode
contractMetadata.Deployer = contract.Deployer
err = generator.permit2Handler(&contractMetadata)
default:
err = fmt.Errorf("unknown contract: %s, don't know how to handle it", contract.Name)
}
if err != nil {
return err
}
}
return nil
}
This diff is collapsed.
package bindgen
import (
"testing"
"github.com/stretchr/testify/require"
)
var generator BindGenGeneratorRemote = BindGenGeneratorRemote{}
func TestRemoveDeploymentSalt(t *testing.T) {
for _, tt := range removeDeploymentSaltTests {
t.Run(tt.name, func(t *testing.T) {
got, _ := generator.removeDeploymentSalt(tt.deploymentData, tt.deploymentSalt)
require.Equal(t, tt.expected, got)
})
}
}
func TestRemoveDeploymentSaltFailures(t *testing.T) {
for _, tt := range removeDeploymentSaltTestsFailures {
t.Run(tt.name, func(t *testing.T) {
_, err := generator.removeDeploymentSalt(tt.deploymentData, tt.deploymentSalt)
require.Equal(t, err.Error(), tt.expectedError)
})
}
}
package bindgen
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"path"
"strings"
"github.com/ethereum/go-ethereum/log"
)
type BindGenGeneratorBase struct {
MetadataOut string
BindingsPackageName string
MonorepoBasePath string
ContractsListPath string
Logger log.Logger
}
type contractsList struct {
Local []string `json:"local"`
Remote []RemoteContract `json:"remote"`
}
// readContractList reads a JSON file from the given `filePath` and unmarshals
// its content into the provided result interface. It logs the path of the file
// being read.
//
// Parameters:
// - logger: An instance of go-ethereum/log
// - filePath: The path to the JSON file to be read.
// - result: A pointer to the structure where the JSON data will be unmarshaled.
//
// Returns:
// - An error if reading the file or unmarshaling fails, nil otherwise.
func readContractList(logger log.Logger, filePath string) (contractsList, error) {
logger.Debug("Reading contract list", "filePath", filePath)
var contracts contractsList
contractData, err := os.ReadFile(filePath)
if err != nil {
return contracts, err
}
return contracts, json.Unmarshal(contractData, &contracts)
}
// mkTempArtifactsDir creates a temporary directory with a "op-bindings" prefix
// for holding contract artifacts. The path to the created directory is logged.
//
// Parameters:
// - logger: An instance of go-ethereum/log
//
// Returns:
// - The path to the created temporary directory.
// - An error if the directory creation fails, nil otherwise.
func mkTempArtifactsDir(logger log.Logger) (string, error) {
dir, err := os.MkdirTemp("", "op-bindings")
if err != nil {
return "", err
}
logger.Debug("Created temporary artifacts directory", "dir", dir)
return dir, nil
}
// writeContractArtifacts writes the provided ABI and bytecode data to respective
// files in the specified temporary directory. The naming convention for these
// files is based on the provided contract name. The ABI data is written to a file
// with a ".abi" extension, and the bytecode data is written to a file with a ".bin"
// extension.
//
// Parameters:
// - logger: An instance of go-ethereum/log
// - tempDirPath: The directory path where the ABI and bytecode files will be written.
// - contractName: The name of the contract, used to create the filenames.
// - abi: The ABI data of the contract.
// - bytecode: The bytecode of the contract.
//
// Returns:
// - The full path to the written ABI file.
// - The full path to the written bytecode file.
// - An error if writing either file fails, nil otherwise.
func writeContractArtifacts(logger log.Logger, tempDirPath, contractName string, abi, bytecode []byte) (string, string, error) {
logger.Debug("Writing ABI and bytecode to temporary artifacts directory", "contractName", contractName, "tempDirPath", tempDirPath)
abiFilePath := path.Join(tempDirPath, contractName+".abi")
if err := os.WriteFile(abiFilePath, abi, 0o600); err != nil {
return "", "", fmt.Errorf("error writing %s's ABI file: %w", contractName, err)
}
bytecodeFilePath := path.Join(tempDirPath, contractName+".bin")
if err := os.WriteFile(bytecodeFilePath, bytecode, 0o600); err != nil {
return "", "", fmt.Errorf("error writing %s's bytecode file: %w", contractName, err)
}
return abiFilePath, bytecodeFilePath, nil
}
// genContractBindings generates Go bindings for an Ethereum contract using
// the provided ABI and bytecode files. The bindings are generated using the
// `abigen` tool and are written to the specified Go package directory. The
// generated file's name is based on the provided contract name and will have
// a ".go" extension. The generated bindings will be part of the provided Go
// package.
//
// Parameters:
// - logger: An instance of go-ethereum/log
// - abiFilePath: The path to the ABI file for the contract.
// - bytecodeFilePath: The path to the bytecode file for the contract.
// - goPackageName: The name of the Go package where the bindings will be written.
// - contractName: The name of the contract, used for naming the output file and
// defining the type in the generated bindings.
//
// Returns:
// - An error if there's an issue during any step of the binding generation process,
// nil otherwise.
//
// Note: This function relies on the external `abigen` tool, which should be
// installed and available in the system's PATH.
func genContractBindings(logger log.Logger, monorepoRootPath, abiFilePath, bytecodeFilePath, goPackageName, contractName string) error {
cwd, err := os.Getwd()
if err != nil {
return fmt.Errorf("error getting cwd: %w", err)
}
outFilePath := path.Join(cwd, goPackageName, strings.ToLower(contractName)+".go")
var existingOutput []byte
if _, err := os.Stat(outFilePath); err == nil {
existingOutput, err = os.ReadFile(outFilePath)
if err != nil {
return fmt.Errorf("error reading existing bindings output file, outFilePath: %s err: %w", outFilePath, err)
}
}
if monorepoRootPath != "" {
logger.Debug("Checking abigen version")
// Fetch installed abigen version (format: abigen version X.Y.Z-<stable/nightly>-<commit_sha>)
cmd := exec.Command("abigen", "--version")
var versionBuf bytes.Buffer
cmd.Stdout = bufio.NewWriter(&versionBuf)
if err := cmd.Run(); err != nil {
return fmt.Errorf("error fetching abigen version: %w", err)
}
abigenVersion := bytes.Trim(versionBuf.Bytes(), "\n")
// Fetch expected abigen version (format: vX.Y.Z)
expectedAbigenVersion, err := readExpectedAbigenVersion(monorepoRootPath)
if err != nil {
return fmt.Errorf("error fetching the expected abigen version: %w", err)
}
if !bytes.Contains(abigenVersion, []byte(expectedAbigenVersion)) {
return fmt.Errorf("abigen version mismatch, expected %s, got %s. Please run `pnpm install:abigen` in the monorepo root", expectedAbigenVersion, abigenVersion)
}
} else {
logger.Debug("No monorepo root path provided, skipping abigen version check")
}
logger.Debug("Generating contract bindings", "contractName", contractName, "outFilePath", outFilePath)
cmd := exec.Command("abigen", "--abi", abiFilePath, "--bin", bytecodeFilePath, "--pkg", goPackageName, "--type", contractName, "--out", outFilePath)
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
return fmt.Errorf("error running abigen for %s: %w", contractName, err)
}
if len(existingOutput) != 0 {
newOutput, err := os.ReadFile(outFilePath)
if err != nil {
return fmt.Errorf("error reading new file: %w", err)
}
if bytes.Equal(existingOutput, newOutput) {
logger.Debug("No changes detected in the contract bindings", "contractName", contractName)
} else {
logger.Warn("Changes detected in the contract bindings, old bindings have been overwritten", "contractName", contractName)
}
} else {
logger.Debug("No existing contract bindings found, skipping comparison", "contractName", contractName)
}
return nil
}
// Versions is a struct for holding the versions of the tools used in the monorepo
type Versions struct {
Abigen string `json:"abigen"`
Foundry string `json:"foundry"`
Geth string `json:"geth"`
Nvm string `json:"nvm"`
Slither string `json:"slither"`
Kontrol string `json:"kontrol"`
}
// readExpectedAbigenVersion reads the expected abigen version from the monorepo's
// versions.json file. This function will remove the 'v' prefix from the version
// string.
//
// Parameters:
// - monorepoRootPath: The path to the monorepo's root directory.
//
// Returns:
// - The expected abigen version.
// - An error if the versions.json file cannot be read or parsed, nil otherwise.
func readExpectedAbigenVersion(monorepoRootPath string) (string, error) {
// Open the version control file
jsonFile, err := os.Open(path.Join(monorepoRootPath, "versions.json"))
if err != nil {
return "", fmt.Errorf("error reading versions.json file: %w", err)
}
defer jsonFile.Close()
// Parse the version control file
byteValue, _ := io.ReadAll(jsonFile)
var versions Versions
if err := json.Unmarshal(byteValue, &versions); err != nil {
return "", fmt.Errorf("error parsing versions.json file: %w", err)
}
// Trim the 'v' prefix from the version string
return strings.Trim(versions.Abigen, "v"), nil
}
package bindgen
import (
"encoding/json"
"os"
"path"
"testing"
"github.com/stretchr/testify/require"
)
func TestReadExpectedAbigenVersion(t *testing.T) {
// Create a temporary directory for the version control file.
tmpDir := path.Join(os.TempDir(), "version-tests")
defer os.RemoveAll(tmpDir)
require.NoError(t, os.MkdirAll(tmpDir, 0755))
// Create a temporary version control file.
versionFile := path.Join(tmpDir, "versions.json")
versions := Versions{Abigen: "v1.2.3"}
// Marshal the versions to JSON.
versionsJSON, err := json.Marshal(versions)
require.NoError(t, err)
// Write the JSON to the version control file.
require.NoError(t, os.WriteFile(versionFile, versionsJSON, 0644))
// Read the expected version from the version control file.
// The read version should not have a "v" prefix.
expectedVersion, err := readExpectedAbigenVersion(tmpDir)
require.NoError(t, err)
require.Equal(t, expectedVersion, "1.2.3")
}
package main
import (
"fmt"
"os"
"github.com/ethereum-optimism/optimism/op-bindings/bindgen"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
op_service "github.com/ethereum-optimism/optimism/op-service"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
)
const (
// Base Flags
MetadataOutFlagName = "metadata-out"
BindingsPackageNameFlagName = "bindings-package"
ContractsListFlagName = "contracts-list"
// Local Contracts Flags
SourceMapsListFlagName = "source-maps-list"
ForgeArtifactsFlagName = "forge-artifacts"
// Remote Contracts Flags
EtherscanApiKeyEthFlagName = "etherscan.apikey.eth"
EtherscanApiKeyOpFlagName = "etherscan.apikey.op"
RpcUrlEthFlagName = "rpc.url.eth"
RpcUrlOpFlagName = "rpc.url.op"
)
func main() {
oplog.SetupDefaults()
app := &cli.App{
Name: "BindGen",
Usage: "Generate contract bindings using Foundry artifacts and/or remotely sourced contract data",
Commands: []*cli.Command{
{
Name: "generate",
Usage: "Generate contract bindings",
Flags: baseFlags(),
Subcommands: []*cli.Command{
{
Name: "all",
Usage: "Generate bindings for local and remote contracts",
Flags: append(localFlags(), remoteFlags()...),
Action: generateBindings,
},
{
Name: "local",
Usage: "Generate bindings for locally sourced contracts",
Flags: localFlags(),
Action: generateBindings,
},
{
Name: "remote",
Usage: "Generate bindings for remotely sourced contracts",
Flags: remoteFlags(),
Action: generateBindings,
},
},
},
},
}
if err := app.Run(os.Args); err != nil {
log.Crit("BindGen error", "error", err.Error())
}
}
func setupLogger(c *cli.Context) log.Logger {
logger := oplog.NewLogger(oplog.AppOut(c), oplog.ReadCLIConfig(c))
oplog.SetGlobalLogHandler(logger.Handler())
return logger
}
func generateBindings(c *cli.Context) error {
logger := setupLogger(c)
switch c.Command.Name {
case "all":
localBindingsGenerator, err := parseConfigLocal(logger, c)
if err != nil {
return err
}
if err := localBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating local bindings: %w", err)
}
remoteBindingsGenerator, err := parseConfigRemote(logger, c)
if err != nil {
return err
}
if err := remoteBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating remote bindings: %w", err)
}
return nil
case "local":
localBindingsGenerator, err := parseConfigLocal(logger, c)
if err != nil {
return err
}
if err := localBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating local bindings: %w", err)
}
return nil
case "remote":
remoteBindingsGenerator, err := parseConfigRemote(logger, c)
if err != nil {
return err
}
if err := remoteBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating remote bindings: %w", err)
}
return nil
default:
return fmt.Errorf("unknown command: %s", c.Command.Name)
}
}
func parseConfigBase(logger log.Logger, c *cli.Context) (bindgen.BindGenGeneratorBase, error) {
cwd, err := os.Getwd()
if err != nil {
return bindgen.BindGenGeneratorBase{}, err
}
monoRepoPath, err := op_service.FindMonorepoRoot(cwd)
if err != nil {
return bindgen.BindGenGeneratorBase{}, err
}
return bindgen.BindGenGeneratorBase{
MetadataOut: c.String(MetadataOutFlagName),
BindingsPackageName: c.String(BindingsPackageNameFlagName),
MonorepoBasePath: monoRepoPath,
ContractsListPath: c.String(ContractsListFlagName),
Logger: logger,
}, nil
}
func parseConfigLocal(logger log.Logger, c *cli.Context) (bindgen.BindGenGeneratorLocal, error) {
baseConfig, err := parseConfigBase(logger, c)
if err != nil {
return bindgen.BindGenGeneratorLocal{}, err
}
return bindgen.BindGenGeneratorLocal{
BindGenGeneratorBase: baseConfig,
SourceMapsList: c.String(SourceMapsListFlagName),
ForgeArtifactsPath: c.String(ForgeArtifactsFlagName),
}, nil
}
func parseConfigRemote(logger log.Logger, c *cli.Context) (bindgen.BindGenGeneratorRemote, error) {
baseConfig, err := parseConfigBase(logger, c)
if err != nil {
return bindgen.BindGenGeneratorRemote{}, err
}
generator := bindgen.BindGenGeneratorRemote{
BindGenGeneratorBase: baseConfig,
}
generator.ContractDataClients.Eth = etherscan.NewEthereumClient(c.String(EtherscanApiKeyEthFlagName))
generator.ContractDataClients.Op = etherscan.NewOptimismClient(c.String(EtherscanApiKeyOpFlagName))
if generator.RpcClients.Eth, err = ethclient.Dial(c.String(RpcUrlEthFlagName)); err != nil {
return bindgen.BindGenGeneratorRemote{}, fmt.Errorf("error initializing Ethereum client: %w", err)
}
if generator.RpcClients.Op, err = ethclient.Dial(c.String(RpcUrlOpFlagName)); err != nil {
return bindgen.BindGenGeneratorRemote{}, fmt.Errorf("error initializing Optimism client: %w", err)
}
return generator, nil
}
func baseFlags() []cli.Flag {
baseFlags := []cli.Flag{
&cli.StringFlag{
Name: MetadataOutFlagName,
Usage: "Output directory to put contract metadata files in",
Required: true,
},
&cli.StringFlag{
Name: BindingsPackageNameFlagName,
Usage: "Go package name given to generated bindings",
Required: true,
},
&cli.StringFlag{
Name: ContractsListFlagName,
Usage: "Path to file containing list of contract names to generate bindings for",
Required: true,
},
}
return append(baseFlags, oplog.CLIFlags("bindgen")...)
}
func localFlags() []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: SourceMapsListFlagName,
Usage: "Comma-separated list of contracts to generate source-maps for",
},
&cli.StringFlag{
Name: ForgeArtifactsFlagName,
Usage: "Path to forge-artifacts directory, containing compiled contract artifacts",
Required: true,
},
}
}
func remoteFlags() []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: EtherscanApiKeyEthFlagName,
Usage: "API key to make queries to Etherscan for Ethereum",
Required: true,
},
&cli.StringFlag{
Name: EtherscanApiKeyOpFlagName,
Usage: "API key to make queries to Etherscan for Optimism",
Required: true,
},
&cli.StringFlag{
Name: RpcUrlEthFlagName,
Usage: "RPC URL (with API key if required) to query Ethereum",
Required: true,
},
&cli.StringFlag{
Name: RpcUrlOpFlagName,
Usage: "RPC URL (with API key if required) to query Optimism",
Required: true,
},
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment