From c76b651eeaeb4c8551aeb9efe0f830818b43435b Mon Sep 17 00:00:00 2001 From: AnishRane Date: Tue, 14 May 2024 18:07:54 +0530 Subject: [PATCH 1/5] setup: .gitignore for solana spl token balance validator --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index de08aae..5b3f419 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .env .local_keys /node_modules +./balance-validator/.env +./balance-validator/sheet.csv \ No newline at end of file From 33f9c25283bf5030d2628f940582125d6d66330e Mon Sep 17 00:00:00 2001 From: AnishRane Date: Tue, 14 May 2024 18:08:31 +0530 Subject: [PATCH 2/5] setup: repository setup for balance validator script --- balance-validator/.gitignore | 2 ++ balance-validator/example.env | 4 ++++ package-lock.json | 2 +- package.json | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 balance-validator/.gitignore create mode 100644 balance-validator/example.env diff --git a/balance-validator/.gitignore b/balance-validator/.gitignore new file mode 100644 index 0000000..1366f3c --- /dev/null +++ b/balance-validator/.gitignore @@ -0,0 +1,2 @@ +.env +/sheet.csv diff --git a/balance-validator/example.env b/balance-validator/example.env new file mode 100644 index 0000000..2aa4fcc --- /dev/null +++ b/balance-validator/example.env @@ -0,0 +1,4 @@ +SOL_RPC_URL= +SPL_TOKEN_ADDRESS= +OUTPUT_FILE_PATH='./' +INPUT_FILE_PATH='./' diff --git a/package-lock.json b/package-lock.json index b9fde71..2c0c483 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "@typescript-eslint/eslint-plugin": "^7.3.1", "@typescript-eslint/parser": "^7.3.1", "eslint": "^8.57.0", - "husky": "^8.0.3", + "husky": "^8.0.0", "lint-staged": "^15.2.2", "prettier": "^3.2.5", "ts-node": "^10.9.1", diff --git a/package.json b/package.json index 634e9e1..ca720bd 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@typescript-eslint/eslint-plugin": "^7.3.1", "@typescript-eslint/parser": "^7.3.1", "eslint": "^8.57.0", - "husky": "^8.0.3", + "husky": "^8.0.0", "lint-staged": "^15.2.2", "prettier": "^3.2.5", "ts-node": "^10.9.1", From 7fe6b224b10484eb30df459a232149ad39e48711 Mon Sep 17 00:00:00 2001 From: AnishRane Date: Tue, 14 May 2024 18:09:08 +0530 Subject: [PATCH 3/5] feat: add solana spl token balance validator script --- balance-validator/balance-validator.py | 100 +++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 balance-validator/balance-validator.py diff --git a/balance-validator/balance-validator.py b/balance-validator/balance-validator.py new file mode 100644 index 0000000..5daaff9 --- /dev/null +++ b/balance-validator/balance-validator.py @@ -0,0 +1,100 @@ +import csv +import requests +import json +from dotenv import load_dotenv +import os + +load_dotenv() + + + +def getTokenBal(walletAddress): + url = os.getenv('SOL_RPC_URL') + SPL_SPL_TOKEN_ADDRESS = os.getenv('SPL_TOKEN_ADDRESS') + + TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + + payload = { + "id": 1, + "jsonrpc": "2.0", + "method": "getTokenAccountsByOwner", + "params": [ + walletAddress, + {"programId": TOKEN_PROGRAM_ID}, + {"encoding": "jsonParsed"}, + ], + } + + headers = {"accept": "application/json", "content-type": "application/json"} + + try: + response = requests.post(url, json=payload, headers=headers) + response.raise_for_status() + except requests.exceptions.RequestException as e: + print(f"Error fetching balance for wallet {walletAddress}: {e}") + return None + + try: + response_data = json.loads(response.text) + except json.JSONDecodeError as e: + print(f"Error decoding JSON response for wallet {walletAddress}: {e}") + return None + + if "result" in response_data and len(response_data["result"]["value"]) > 0: + for tokens in response_data["result"]["value"]: + if tokens["account"]["data"]["parsed"]["info"]["mint"] == SPL_SPL_TOKEN_ADDRESS: + brokieBal = tokens["account"]["data"]["parsed"]["info"]["tokenAmount"]["uiAmount"] + return brokieBal + else: + print(f"No accounts found for wallet {walletAddress}") + return None + + +def writeResultsToCSV(results,output_file_path): + with open(output_file_path,mode="a",newline="",encoding="utf-8") as csvfile: + fieldNames = ['Address','TelegramID','Balance','SolScanUrl'] + writer = csv.DictWriter(csvfile,fieldnames=fieldNames) + + writer.writeheader() + for result in results: + writer.writerow(result) + + +def filterMBC(csv_file_path,minAmountHolding): + solscan_account_lookup_url="https://solscan.io/account/" + results = [] + with open(csv_file_path, mode="r", encoding="utf-8") as csfile: + reader = csv.DictReader(csfile) + print("Filtering MBC Defaulters") + for row in reader: + if row['InGroup?']: + print(f"checking wallet:{row['SOLWalletAddress']}") + TargetTokenBal = getTokenBal(row['SOLWalletAddress']) + if TargetTokenBal is not None: + if TargetTokenBal < minAmountHolding: + result ={'Address':row["SOLWalletAddress"],'TelegramID':row['TelegramID'],'Balance':TargetTokenBal,'SolScanUrl':solscan_account_lookup_url+row["SOLWalletAddress"]} + results.append(result) + else: + print(f"Error: Could not fetch balance for wallet {row['SOLWalletAddress']}. Skipping.") + + return results + + + +input_file_name = input("Enter the input file name: ") +output_file_name = input("Enter the name of output file: ") + +output_file_path = os.getenv('OUTPUT_FILE_PATH') +input_file_path = os.getenv('INPUT_FILE_PATH') + + +input_file = input_file_path+input_file_name+'.csv' + +# Declare min amount that you want to configure +minAmountHolding = 1000000 +results = filterMBC(input_file,minAmountHolding) + +output_file = (output_file_path+output_file_name+'.csv') +writeResultsToCSV(results,output_file) + + From 55f4307b684d9cc1c02baf8c7be24c7a5b2cf9c9 Mon Sep 17 00:00:00 2001 From: AnishRane Date: Tue, 14 May 2024 18:09:52 +0530 Subject: [PATCH 4/5] docs: add README.md and requirements.txt essential for project setup --- balance-validator/README.md | 20 ++++++++++++++++++++ balance-validator/requirements.txt | 6 ++++++ 2 files changed, 26 insertions(+) create mode 100644 balance-validator/README.md create mode 100644 balance-validator/requirements.txt diff --git a/balance-validator/README.md b/balance-validator/README.md new file mode 100644 index 0000000..7129139 --- /dev/null +++ b/balance-validator/README.md @@ -0,0 +1,20 @@ +## 🛠️ How to run + +1. Install required packages +```bash + pip install requirements.txt + ``` + +2. #### Setting up script + - Open the [script](./mbcValidator.py) + - Ref [example.env](./example.env) to setup required env variables. + +3. #### Run script + + ```bash + python mbcValidator.py + ``` + +>**Note:** It would ask input csv name and output csv name + + diff --git a/balance-validator/requirements.txt b/balance-validator/requirements.txt new file mode 100644 index 0000000..f27b2be --- /dev/null +++ b/balance-validator/requirements.txt @@ -0,0 +1,6 @@ +certifi==2024.2.2 +charset-normalizer==3.3.2 +idna==3.7 +python-dotenv==1.0.1 +requests==2.31.0 +urllib3==2.2.1 From a596427eee2e70ddafeab02c1e19e4479b1e01b1 Mon Sep 17 00:00:00 2001 From: AnishRane Date: Tue, 14 May 2024 18:14:25 +0530 Subject: [PATCH 5/5] docs: update root README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 7299458..ee12da9 100644 --- a/README.md +++ b/README.md @@ -45,3 +45,8 @@ This script helps to transfer specified amount of tokens to target address passe #### `updateTokenMetadata.ts` This [updateTokenMetadata](./scripts/updateTokenMetadata.ts) script helps to update metadata of token if we need to rectify anything. + +#### `balance-validator.py` + +This [balance-validator](./balance-validator/balance-validator.py) script helps spl-token community admins to implement various gamifications with token holders +inititaly this script provides a filtering mechanism based on wallet address token holding balance but can be expanded to other features.