Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
theredrad committed Oct 3, 2021
0 parents commit da1916c
Show file tree
Hide file tree
Showing 8 changed files with 1,492 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
on:
release:
types: [created]

jobs:
releases-matrix:
name: Release Go binaries
runs-on: ubuntu-latest
strategy:
matrix:
goos: [ linux, windows, darwin ]
goarch: [ "386", amd64 ]
exclude:
- goarch: "386"
goos: darwin
steps:
- uses: actions/checkout@v2
- uses: wangyoucao577/[email protected]
with:
github_token: ${{ secrets.GH_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.idea
config.yaml
list.json
output.json
/bin
.DS_Store
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
build: build-linux build-mac build-windows

build-linux:
CGO_ENABLED=0 GOOS=linux go build -mod=readonly -a -ldflags "-w -s" -o ./bin/resolver-linux main.go
build-mac:
CGO_ENABLED=0 GOOS=darwin go build -mod=readonly -a -ldflags "-w -s" -o ./bin/resolver-mac main.go
build-windows:
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -o ./bin/resolver.exe main.go
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# ENS batch domain resolver (.eth domain)
A simple program to check a batch of ENS domains availability.

## Configure
Configs store in `config.yaml` file next to the main file. an example of the config file exists.

### `client-endpoint`
To connect to the Ethereum network, you need to create an account in https://infura.io & put your API URL in the config.yml as `client-endpoint`.

### `list-file`
The `list-file` is the path of a json file with an object with an array of domains which is named `domains`.
Example:
```json
{
"domains": [
"abacus",
"abased",
"abated",
"abates",
"abayas"
]
}
```
### `output-file`
The `output-file` is the path of output file.

## Run
You can pull the source & run it via `go run main.go` or download the binaries from the release page. make sure the binary file is executable & run it from the terminal `./resolver`.
3 changes: 3 additions & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
client-endpoint: "https://mainnet.infura.io/v3/YOUR_APP_ID"
list-file: "list.json"
output-file: "output.json"
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module resolver

go 1.16

require (
github.com/ethereum/go-ethereum v1.10.8
github.com/spf13/viper v1.8.1
github.com/wealdtech/go-ens/v3 v3.5.1
)
1,276 changes: 1,276 additions & 0 deletions go.sum

Large diffs are not rendered by default.

140 changes: 140 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"sync"
"time"

"github.com/ethereum/go-ethereum/ethclient"
"github.com/spf13/viper"
"github.com/wealdtech/go-ens/v3"
)

type List struct {
Domains []string
}

type Domain struct {
Name string `json:"name"`
Address string `json:"address"`
}

type Output struct {
Available []*Domain //available domains
NotAvailable []*Domain // already registered domains
NoResolver []*Domain // no resolver found
NoAddress []*Domain // no address found
}

var (
unregisteredDomainErrStr = "unregistered name"
noResolverErrStr = "no resolver"
noAddressErrStr = "no address"
)

func init() {
viper.SetConfigFile("./config.yaml")

err := viper.ReadInConfig()
if err != nil {
panic("failed to read config file")
}
}

func main() {
if viper.GetString("client-endpoint") == "" {
panic("client-endpoint is required, please register in infura.io, create a project & copy the http endpoint to the config file")
}

lf, err := ioutil.ReadFile(viper.GetString("list-file"))
if err != nil {
panic(err)
}

list := &List{}
err = json.Unmarshal(lf, list)
if err != nil {
panic(err)
}

client, err := ethclient.Dial(viper.GetString("client-endpoint"))
if err != nil {
panic(err)
}

o := &Output{}
var wg sync.WaitGroup
for i, d := range list.Domains {
wg.Add(1)
go func(d string) {
defer wg.Done()
log.Printf("resolving %s.eth", d)
address, err := ens.Resolve(client, fmt.Sprintf("%s.eth", d))
if err != nil {
switch err.Error() {
case unregisteredDomainErrStr:
o.Available = append(o.Available, &Domain{
Name: fmt.Sprintf("%s.eth", d),
})
case noResolverErrStr:
o.NoResolver = append(o.Available, &Domain{
Name: fmt.Sprintf("%s.eth", d),
})
case noAddressErrStr:
o.NoAddress = append(o.NoAddress, &Domain{
Name: fmt.Sprintf("%s.eth", d),
})
default:
log.Printf("error while resolving address %s.eth: %v", d, err)
}
return
}

o.NotAvailable = append(o.NotAvailable, &Domain{
Name: fmt.Sprintf("%s.eth", d),
Address: address.String(),
})
}(d)

if (i+1)%100 == 0 { // sleep to prevent API abuse
time.Sleep(5 * time.Second)
}
}

wg.Wait()
log.Printf("all domain checked, storing to output file")
err = storeOutput(o, viper.GetString("output-file"))
if err != nil {
log.Printf("error while storing the output file: %s", err)
dumpData(o)
return
}
log.Printf("%s saved", viper.GetString("output-file"))
}

func storeOutput(output *Output, file string) error {
b, err := json.Marshal(output)
if err != nil {
return err
}

f, err := os.Create(file)
if err != nil {
return err
}
defer f.Close()

_, err = f.Write(b)
if err != nil {
return err
}
return nil
}

func dumpData(o *Output) {
fmt.Printf("=======\nDUMPING DATA:\n%#v\n", o)
}

0 comments on commit da1916c

Please sign in to comment.