diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..f5fc8f8 Binary files /dev/null and b/.DS_Store differ diff --git a/.github/workflows/tg-notify.yml b/.github/workflows/tg-notify.yml new file mode 100644 index 0000000..53028de --- /dev/null +++ b/.github/workflows/tg-notify.yml @@ -0,0 +1,20 @@ +name: tg-notify +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Update status + uses: appleboy/telegram-action@master + with: + to: ${{ secrets.TELEGRAM_TO }} + token: ${{ secrets.TELEGRAM_TOKEN }} + message: | #https://help.github.com/en/actions/reference/contexts-and-expression-syntax-for-github-actions#github-context + ${{ github.actor }} created commit: + Commit message: ${{ github.event.head_commit.message }} + + Repository: ${{ github.repository }} + + Branch: ${{ github.ref_name }} + + See changes: https://github.com/${{ github.repository }}/commit/${{github.sha}} diff --git a/README.md b/README.md index 060bcd0..b63142c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,99 @@ # MultiPay + A Sentinel DVPN Multipay Transactor + +This will run in a loop and prompt you for sentinel wallet addresses and amounts that you would like to send in single transaction (batch sending) based on the seed phrase you specify in the scrtxxs file. + +# Installation + +* requires sentinel-sdk + +* requires >= python 3.10 + +To install the dependency: + +```shell +pip install sentinel-sdk +``` + +Clone the repository + +```shell +git clone https://github.com/MathNodes/MultiPay +``` + +# Configuration + +Within the repository directory, edit the **scrtxxs.py** to your specific parameters. + +* WalletName - The name you will give your sending wallet in the krygin + +* HotWalletPW - The Password for your wallet in the keyring + +* WalletSeed - The seed phrase of the sending wallet if not already in the keyring. leave blank if you already imported this wallet once before + +# Run + +To run the MultiPay script do the following: + +```shell +python3 SentinelMultiPay.py +``` + +and follow the on screen prompts + +# Logs & Keyring + +The log file will be in the following folders + +OS X: + +```shell +/Users/username/.meile-multi-pay/multipay.log +``` + +Linux: + +```shell +/home/username/.meile-multi-pay/multipay.log +``` + +This is also the folder the encrypted keyring will reside in. + +# Donations + +Because we are working on a small grant with no VC funding, any additional contributions to our developer team is more than certainly welcomed. It will help fund future releases. + +## BTC (Bitcoin) + +``` +bc1qtvc9l3cr9u4qg6uwe6pvv7jufvsnn0xxpdyftl +``` + +![BTC](./img/BTC.png) + +## DVPN (Sentinel) + +``` +sent12v8ghhg98e2n0chyje3su4uqlsg75sh4lwcyww +``` + +![dvpn](./img/DVPN.png) + +## XMR (Monero) + +``` +87qHJPU5dZGWaWzuoC3My5SgoQSuxh4sHSv1FXRZrQ9XZHWnfC33EX1NLv5HujpVhbPbbF9RcXXD94byT18HonAQ75b9dyR +``` + +![xmr](./img/XMR.png) + +## ARRR (Pirate Chain) + +``` +zs1gn457262c52z5xa666k77zafqmke0hd60qvc38dk48w9fx378h4zjs5rrwnl0x8qazj4q3x4svz +``` + + + +![ARRR](./img/ARRR.png) diff --git a/SentinelMultiPay.py b/SentinelMultiPay.py new file mode 100644 index 0000000..609b982 --- /dev/null +++ b/SentinelMultiPay.py @@ -0,0 +1,184 @@ +#!/bin/env python3 + +import scrtxxs +import requests +import sys +from os import path, mkdir +from urllib.parse import urlparse +from bip_utils import Bip39SeedGenerator, Bip44, Bip44Coins + +from sentinel_sdk.sdk import SDKInstance +from sentinel_sdk.types import TxParams +from keyrings.cryptfile.cryptfile import CryptFileKeyring +from sentinel_protobuf.cosmos.base.v1beta1.coin_pb2 import Coin +import ecdsa +import hashlib +import bech32 +from mospy import Transaction +from grpc import RpcError + +from datetime import datetime + +MNAPI = "https://api.sentinel.mathnodes.com" +NODEAPI = "/sentinel/nodes/%s" +GRPC = scrtxxs.GRPC +SSL = True +VERSION = 20240817.0234 +SATOSHI = 1000000 + +class MultiPay(): + def __init__(self, keyring_passphrase, wallet_name, seed_phrase = None): + self.wallet_name = wallet_name + + if seed_phrase: + seed_bytes = Bip39SeedGenerator(seed_phrase).Generate() + bip44_def_ctx = Bip44.FromSeed(seed_bytes, Bip44Coins.COSMOS).DeriveDefaultPath() + privkey_obj = ecdsa.SigningKey.from_string(bip44_def_ctx.PrivateKey().Raw().ToBytes(), curve=ecdsa.SECP256k1) + pubkey = privkey_obj.get_verifying_key() + s = hashlib.new("sha256", pubkey.to_string("compressed")).digest() + r = hashlib.new("ripemd160", s).digest() + five_bit_r = bech32.convertbits(r, 8, 5) + account_address = bech32.bech32_encode("sent", five_bit_r) + print(account_address) + self.keyring = self.__keyring(keyring_passphrase) + self.keyring.set_password("meile-multi-pay", wallet_name, bip44_def_ctx.PrivateKey().Raw().ToBytes().hex()) + else: + self.keyring = self.__keyring(keyring_passphrase) + + private_key = self.keyring.get_password("meile-multi-pay", self.wallet_name) + + grpcaddr, grpcport = urlparse(GRPC).netloc.split(":") + + self.sdk = SDKInstance(grpcaddr, int(grpcport), secret=private_key, ssl=SSL) + + self.logfile = open(path.join(scrtxxs.KeyringDIR, "multipay.log"), "a+") + + now = datetime.now() + self.logfile.write(f"\n---------------------------{now}---------------------------\n") + + def __keyring(self, keyring_passphrase: str): + if not path.isdir(scrtxxs.KeyringDIR): + mkdir(scrtxxs.KeyringDIR) + + kr = CryptFileKeyring() + kr.filename = "keyring.cfg" + kr.file_path = path.join(scrtxxs.KeyringDIR, kr.filename) + kr.keyring_key = keyring_passphrase + return kr + + def __get_balance(self, address): + CoinDict = {'dvpn' : 0, 'scrt' : 0, 'dec' : 0, 'atom' : 0, 'osmo' : 0} + #CoinDict = {'tsent' : 0, 'scrt' : 0, 'dec' : 0, 'atom' : 0, 'osmo' : 0} + endpoint = "/bank/balances/" + address + try: + r = requests.get(MNAPI + endpoint) + coinJSON = r.json() + except: + return None + + print(coinJSON) + try: + for coin in coinJSON['result']: + if "udvpn" in coin['denom']: + CoinDict['dvpn'] = int(coin['amount']) + except Exception as e: + print(str(e)) + return None + return CoinDict + + def SendDVPNs(self, addr_amts): + balance = self.__get_balance(self.sdk._account.address) + wallet_balance = int(balance.get("dvpn", 0)) + + amt = 0 + + # Sum total amount + for amount in addr_amts.values(): + amt += int(amount) + + if wallet_balance < int(amt): + self.logfile.write(f"[sp]: Balance is too low, required: {amt}udvpn, found: {wallet_balance}udvpn\n") + return False + + tx_params = TxParams( + gas=300000, + gas_multiplier=1.15, + fee_amount=30000, + denom="udvpn" + ) + + tx = Transaction( + account=self.sdk._account, + fee=Coin(denom=tx_params.denom, amount=f"{tx_params.fee_amount}"), + gas=tx_params.gas, + protobuf="sentinel", + chain_id="sentinelhub-2", + ) + + + for addr,udvpn in addr_amts.items(): + tx.add_msg( + tx_type='transfer', + sender=self.sdk._account, + receipient=addr, + amount=udvpn, + denom="udvpn", + ) + + self.sdk._client.load_account_data(account=self.sdk._account) + + if tx_params.gas == 0: + self.sdk._client.estimate_gas( + transaction=tx, update=True, multiplier=tx_params.gas_multiplier + ) + + tx_height = 0 + try: + tx = self.sdk._client.broadcast_transaction(transaction=tx) + + except RpcError as rpc_error: + details = rpc_error.details() + print("details", details) + print("code", rpc_error.code()) + print("debug_error_string", rpc_error.debug_error_string()) + self.logfile.write("[sp]: RPC ERROR. ") + return False + + if tx.get("log", None) is None: + tx_response = self.sdk.nodes.wait_for_tx(tx["hash"]) + tx_height = tx_response.get("txResponse", {}).get("height", 0) if isinstance(tx_response, dict) else tx_response.tx_response.height + + message = f"Succefully sent {amt}udvpn at height: {tx_height} distributed by {addr_amts}" if tx.get("log", None) is None else tx["log"] + self.logfile.write(f"[sp]: {message}\n") + return True + + +if __name__ == "__main__": + mp = MultiPay(scrtxxs.HotWalletPW, scrtxxs.WalletName, scrtxxs.WalletSeed) + + SendDict = {} + + print(f"Leeloo Dallas Multipay - A DVPN multipay transactor - by freQniK - version: 5th Element {VERSION}\n\n") + print("You will be presented with a loop to enter Sentinel wallet addresses and amt. When finished, enter 'done'") + while True: + addr = input("Enter wallet address: ") + if addr.upper() == "DONE": + break + amt = input("Enter dvpn amt to send to wallet: ") + + SendDict[addr] = str(int(float(amt) / SATOSHI)) + + print("The following addresses will receive these repsective amounts: ") + print(SendDict) + answer = input("Would you iike to continue (Y/n): ") + if answer.upper() == "Y": + if mp.SendDVPNs(SendDict): + print("Transaction completed successfully. Please check the log file") + print(f"{scrtxxs.KeyringDIR}/multipay.log") + else: + print("Something went wrong. Please check the log file.") + print(f"{scrtxxs.KeyringDIR}/multipay.log") + else: + sys.exit(0) + + \ No newline at end of file diff --git a/img/ARRR.png b/img/ARRR.png new file mode 100644 index 0000000..8c87e4f Binary files /dev/null and b/img/ARRR.png differ diff --git a/img/BTC.png b/img/BTC.png new file mode 100644 index 0000000..1f97439 Binary files /dev/null and b/img/BTC.png differ diff --git a/img/DVPN.png b/img/DVPN.png new file mode 100644 index 0000000..32181a7 Binary files /dev/null and b/img/DVPN.png differ diff --git a/img/XMR.png b/img/XMR.png new file mode 100644 index 0000000..8eb6b2b Binary files /dev/null and b/img/XMR.png differ diff --git a/scrtxxs.py b/scrtxxs.py new file mode 100644 index 0000000..ba9beac --- /dev/null +++ b/scrtxxs.py @@ -0,0 +1,28 @@ +''' +You need to edit the following variables below with your desired values: + +WalletName - Whatever you want to name the wallet in the keyring +HotWalletPW - Passowrd for your wallet in the keyring +WalletSeed - Seed if it is a new wallet, o/w it will pull from the keyring the WalletName + +''' + + +import pwd +import os + +import platform + +pltform = platform.system() + +if pltform == "Darwin": + KeyringDIR = "/Users/" + str(pwd.getpwuid(os.getuid())[0]) + "/.meile-multi-pay" +else: + KeyringDIR = "/home/" + str(pwd.getpwuid(os.getuid())[0]) + "/.meile-multi-pay" + +WalletName = "" +HotWalletPW = "" +WalletSeed = "" +GRPC = "https://grpc.bluefren.xyz:443" + +