Last active
December 2, 2023 15:23
-
-
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`
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
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