Skip to content

Instantly share code, notes, and snippets.

@cloakd
Last active December 2, 2023 15:23
Show Gist options
  • Save cloakd/ec5b0d9d19badeee17c0d05059c02cb7 to your computer and use it in GitHub Desktop.
Save cloakd/ec5b0d9d19badeee17c0d05059c02cb7 to your computer and use it in GitHub Desktop.
Jupiter airdrop wallet checker - have all wallets in `users.csv` & specify the column to use via `-column`
package main
import (
"encoding/csv"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
"time"
)
// Jupiter airdrop checker
// Input: `users.csv` (Must have the users wallet address)
// Output: `jupiter_airdrop.csv`
// Flags:
// - `workers` Amount of worker threads to use
// - `column` Column the users wallet address is in the CSV
// - `skip-blank` Skip writing users who are not eligible to the output CSV
// Usage: `go run ./cli/jupiter_airdrop_check.go -column 3 -skip-blank -workers 100`
type airdropCheckResp struct {
Owner string `json:"owner"`
TokensFinal string `json:"tokens_final"`
TokensTier string `json:"tokens_tier"`
TokensOgBonus string `json:"tokens_og_bonus"`
TokensWelcome string `json:"tokens_welcome"`
Tier string `json:"tier"`
Score string `json:"score"`
Volume string `json:"volume"`
CheckOg string `json:"check_og"`
Check2023Multiplier string `json:"check_2023_multiplier"`
CheckConsistency string `json:"check_consistency"`
CheckLoDca string `json:"check_lo_dca"`
LikelyBot string `json:"likely_bot"`
LikelyCluster string `json:"likely_cluster"`
DebugProductScore string `json:"debug_product_score"`
DebugSwapScore string `json:"debug_swap_score"`
DebugConsistencyScore string `json:"debug_consistency_score"`
Debug2023 string `json:"debug_2023"`
DebugTxFailure string `json:"debug_tx_failure"`
Hacker string `json:"hacker"`
DebugRank string `json:"debug_rank"`
}
func (a *airdropCheckResp) Row() []string {
return []string{
a.Owner,
a.TokensFinal,
a.TokensTier,
a.TokensOgBonus,
a.TokensWelcome,
a.Tier,
a.Score,
a.Volume,
a.CheckOg,
a.Check2023Multiplier,
a.CheckConsistency,
a.CheckLoDca,
a.LikelyBot,
a.LikelyCluster,
a.DebugProductScore,
a.DebugSwapScore,
a.DebugConsistencyScore,
a.Debug2023,
a.DebugTxFailure,
a.Hacker,
a.DebugRank,
}
}
type jupiterAirdropCheck struct {
client *http.Client
skipBlank bool
walletInColumn int
workerCount int
inCh chan string
outCh chan *airdropCheckResp
}
func main() {
skipBlank := flag.Bool("skip-blank", false, "Skip writing wallets to file that do not qualify")
walletInColumn := flag.Int("column", 0, "Column in the csv that contains the wallet address")
workerCount := flag.Int("workers", 50, "Workers to use")
flag.Parse()
svc := jupiterAirdropCheck{
skipBlank: *skipBlank,
walletInColumn: *walletInColumn,
workerCount: *workerCount,
client: &http.Client{Timeout: 2 * time.Second},
}
err := svc.Run()
if err != nil {
log.Fatal(err)
}
}
func (svc *jupiterAirdropCheck) Run() error {
f, err := os.Open("./users.csv")
if err != nil {
return err
}
defer f.Close()
fn, err := os.Create("./jupiter_airdrop.csv")
if err != nil {
return err
}
defer fn.Close()
w := csv.NewWriter(fn)
defer w.Flush()
err = w.Write(svc.header())
if err != nil {
return err
}
r := csv.NewReader(f)
records, err := r.ReadAll()
if err != nil {
return err
}
log.Println("Wallet in column:", svc.walletInColumn)
log.Println("Skip Blank:", svc.skipBlank)
log.Println("Worker Count:", svc.workerCount)
log.Println("Records to check:", len(records))
time.Sleep(2 * time.Second) //Give the user a little time to check their settings
svc.inCh = make(chan string, len(records))
svc.outCh = make(chan *airdropCheckResp)
for _, record := range records {
svc.inCh <- record[3]
}
svc.startWorkers()
//close(svc.inCh)
log.Println("Listening for records")
for i := 0; i < len(records); i++ {
resp := <-svc.outCh
log.Println(i, records[i][svc.walletInColumn])
if resp == nil {
if svc.skipBlank {
continue
}
err = w.Write([]string{records[i][svc.walletInColumn]}) //Write blank row
} else {
log.Println(i, resp.Owner, resp.Score)
err = w.Write(resp.Row())
}
if err != nil {
return err
}
}
close(svc.outCh)
w.Flush()
return nil
}
func (svc *jupiterAirdropCheck) startWorkers() {
log.Printf("Starting %v workers", svc.workerCount)
for i := 0; i < svc.workerCount; i++ {
go svc.checkWorker()
}
}
func (svc *jupiterAirdropCheck) checkWorker() {
for r := range svc.inCh {
res, err := svc.check(r)
if err != nil {
log.Println(res, "checkWorker err", err)
}
svc.outCh <- res
}
}
func (svc *jupiterAirdropCheck) check(addr string) (*airdropCheckResp, error) {
resp, err := svc.client.Get(fmt.Sprintf("https://jup-airdrop.zhen8558.workers.dev/allocation/%s", strings.ToLower(addr)))
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
log.Println("Invalid resp", resp.StatusCode)
return nil, errors.New(resp.Status)
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if len(data) == 0 {
return nil, nil
}
var dResp airdropCheckResp
err = json.Unmarshal(data, &dResp)
if err != nil {
return nil, err
}
return &dResp, nil
}
func (svc *jupiterAirdropCheck) header() []string {
return []string{
"owner",
"tokens_final",
"tokens_tier",
"tokens_og_bonus",
"tokens_welcome",
"tier",
"score",
"volume",
"check_og",
"check_2023_multiplier",
"check_consistency",
"check_lo_dca",
"likely_bot",
"likely_cluster",
"debug_product_score",
"debug_swap_score",
"debug_consistency_score",
"debug_2023",
"debug_tx_failure",
"hacker",
"debug_rank",
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment