-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add minimal implementation of the hardhat abigen generator helper
- Loading branch information
Showing
9 changed files
with
294 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
build: | ||
go build -o hardhat-abigen main.go |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module github.com/vpavlin/hardhat-abigen | ||
|
||
go 1.18 | ||
|
||
require ( | ||
github.com/sirupsen/logrus v1.9.0 // indirect | ||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= | ||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= | ||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package abigen | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"os/exec" | ||
) | ||
|
||
func Run(in string, typ string, pkg string, output string) error { | ||
args := []string{ | ||
"-abi", in, | ||
"-out", output, | ||
"-type", typ, | ||
"-pkg", pkg, | ||
} | ||
|
||
cmd := exec.Command("abigen", args...) | ||
|
||
var stdErr bytes.Buffer | ||
cmd.Stderr = &stdErr | ||
|
||
err := cmd.Run() | ||
if err != nil { | ||
return fmt.Errorf("Failed to generate bindings: %s, stderr: %s", err, stdErr.String()) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
package extractor | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"io/fs" | ||
"io/ioutil" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/sirupsen/logrus" | ||
"github.com/vpavlin/hardhat-abigen/internal/abigen" | ||
"github.com/vpavlin/hardhat-abigen/internal/types" | ||
"github.com/vpavlin/hardhat-abigen/internal/utils" | ||
) | ||
|
||
func Extract(in io.Reader) (*types.ABI, error) { | ||
bytes, err := ioutil.ReadAll(in) | ||
if err != nil { | ||
return nil, err | ||
} | ||
abi := new(types.ABI) | ||
err = json.Unmarshal(bytes, abi) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if abi.ABI == nil || len(abi.ABI.([]interface{})) == 0 || abi.ByteCode == "" || abi.ByteCode == "0x" { | ||
return nil, nil | ||
} | ||
|
||
return abi, nil | ||
} | ||
|
||
func Dump(out io.Writer, abi *types.ABI) error { | ||
marshalled, err := json.Marshal(abi.ABI) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = out.Write(marshalled) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func ExtractFromFile(in string, out string) (string, error) { | ||
path, err := filepath.Abs(in) | ||
if err != nil { | ||
return "", nil | ||
} | ||
|
||
fp, err := os.Open(path) | ||
if err != nil { | ||
return "", err | ||
} | ||
defer fp.Close() | ||
|
||
abi, err := Extract(fp) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
if abi == nil { | ||
return "", nil | ||
} | ||
|
||
fpOut, err := os.Create(out) | ||
if err != nil { | ||
return "", err | ||
} | ||
defer fpOut.Close() | ||
|
||
err = Dump(fpOut, abi) | ||
if err != nil { | ||
return "", nil | ||
} | ||
|
||
return abi.ContractName, nil | ||
} | ||
|
||
func ExtractWalk(outDir string, p string, info fs.FileInfo, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if info.IsDir() { | ||
dir, err := ioutil.ReadDir(p) | ||
if err != nil { | ||
return err | ||
} | ||
for _, fInfo := range dir { | ||
newPath := path.Join(p, fInfo.Name()) | ||
filepath.WalkDir(newPath, func(path string, d fs.DirEntry, err error) error { | ||
return nil //ExtractWalk(path, info, err) | ||
}) | ||
} | ||
} | ||
|
||
//outFile := path.Join(outDir, info.Name | ||
|
||
return nil | ||
|
||
} | ||
|
||
func Excluded(toCheck string, exclude string) bool { | ||
for _, item := range strings.Split(exclude, ",") { | ||
if strings.Contains(toCheck, item) { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func ProcessSingle(inFile string, outDir string, generateBindings bool, exclude string) error { | ||
if Excluded(inFile, exclude) { | ||
logrus.Infof("Skipping path %s based on --exclude", inFile) | ||
return nil | ||
} | ||
|
||
abiOutDir, err := utils.MkOutDirIfNotExist(outDir, utils.AbiDir) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if len(inFile) == 0 { | ||
return fmt.Errorf("You need to provide a patch to the JSON file containing ABI produced by Hardhat") | ||
} | ||
|
||
abiOutFile := path.Join(abiOutDir, filepath.Base(inFile)) | ||
|
||
contractName, err := ExtractFromFile(inFile, abiOutFile) | ||
if err != nil { | ||
return fmt.Errorf("Failed to extract abi: %s", err) | ||
} | ||
|
||
if generateBindings && len(contractName) > 0 { | ||
bindingsOutDir, err := utils.MkOutDirIfNotExist(outDir, utils.BindingsDir) | ||
if err != nil { | ||
return err | ||
} | ||
bindingsOutFile := path.Join(bindingsOutDir, fmt.Sprintf("%s.%s", contractName, "go")) | ||
logrus.Infof("Generating bindings for %s", contractName) | ||
err = abigen.Run(abiOutFile, contractName, "bindings", bindingsOutFile) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func ProcessAll(inFile string, outDir string, generateBindings bool, exclude string) error { | ||
return filepath.Walk(inFile, func(p string, info fs.FileInfo, err error) error { | ||
if filepath.Ext(p) == ".json" { | ||
return ProcessSingle(p, outDir, generateBindings, exclude) | ||
} | ||
return nil | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package types | ||
|
||
type ABI struct { | ||
ContractName string `json:"contractName"` | ||
ABI interface{} `json:"abi"` | ||
ByteCode string `json:"bytecode"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package utils | ||
|
||
const ( | ||
AbiDir = "abi" | ||
BindingsDir = "bindings" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package utils | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path" | ||
) | ||
|
||
func MkOutDirIfNotExist(prefix string, dir string) (string, error) { | ||
newPath := path.Join(prefix, dir) | ||
info, err := os.Stat(newPath) | ||
if err != nil { | ||
err = os.MkdirAll(newPath, 0777) | ||
if err != nil { | ||
return "", fmt.Errorf("Failed to create output dir: %s", err) | ||
} | ||
} else { | ||
if !info.IsDir() { | ||
return "", fmt.Errorf("Output path already exists, but is not a directory.") | ||
} | ||
} | ||
|
||
return newPath, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/sirupsen/logrus" | ||
"github.com/vpavlin/hardhat-abigen/internal/extractor" | ||
) | ||
|
||
func main() { | ||
|
||
flag.Usage = func() { | ||
fmt.Fprintf(os.Stderr, "Usage: %s [options] [FILE|DIRECTORY]\n", os.Args[0]) | ||
|
||
flag.VisitAll(func(f *flag.Flag) { | ||
fmt.Fprintf(os.Stderr, " --%s\n\t %v (default: '%s')\n", f.Name, f.Usage, f.DefValue) // f.Name, f.Value | ||
}) | ||
} | ||
|
||
outDir := flag.String("outDir", "output", "Destination directory for extracted ABI json files and generated bindings") | ||
generateBindings := flag.Bool("bindings", true, "Use Abigen to generate bindings") | ||
exclude := flag.String("exclude", "", "List of strings to match aginst paths to exclude them from processing") | ||
|
||
flag.Parse() | ||
|
||
inFile := flag.Arg(0) | ||
|
||
info, err := os.Stat(inFile) | ||
if err != nil { | ||
logrus.Errorf("No file provided") | ||
flag.Usage() | ||
os.Exit(1) | ||
} | ||
|
||
if info.IsDir() { | ||
extractor.ProcessAll(inFile, *outDir, *generateBindings, *exclude) | ||
} else { | ||
extractor.ProcessSingle(inFile, *outDir, *generateBindings, *exclude) | ||
} | ||
|
||
} |