#!/usr/bin/env python3 import sys, re, os.path, json, ast from shutil import copyfile if not os.path.isfile("userEnv.py"): copyfile("userEnv.py.template", "userEnv.py") from termcolor import colored from userEnv import dunikey, node from natools import fmt, sign, get_privkey from gql import gql, Client from gql.transport.aiohttp import AIOHTTPTransport if not (dunikey): print("Please set the path to your pubsec keychain in userEnv.py file.") sys.exit(1) # Define Duniter GVA node transport = AIOHTTPTransport(url=node) client = Client(transport=transport, fetch_schema_from_transport=True) class Transaction(): def __init__(self, recipient, amount, comment=''): self.recipient = recipient self.amount = amount self.comment = comment self.issuer = get_privkey(dunikey, "pubsec").pubkey def genDoc(self): # TODO: Check args # Build TX generation document queryBuild = gql( """ query ($recipient: String!, $issuer: String!, $amount: Int!, $comment: String!){ genTxs( amount: $amount comment: $comment issuer: $issuer recipient: $recipient ) } """ ) paramsBuild = { "recipient": self.recipient, "issuer": self.issuer, "amount": self.amount, "comment": self.comment } # Send TX document try: self.txDoc = str(client.execute(queryBuild, variable_values=paramsBuild))[13:-3].replace('\\n','\n') return self.txDoc except Exception as e: message = ast.literal_eval(str(e))["message"] sys.stderr.write("Echec de la génération du document:\n" + message + "\n") sys.exit(1) # Check document def checkTXDoc(self): docList = self.txDoc.splitlines() for i, line in enumerate(docList): if re.search("Issuers:", line): issuerRaw = docList[(i + 1) % len(docList)] if re.search("Outputs:", line): outputRaw = docList[(i + 1) % len(docList)].split(":") outAmount = outputRaw[0] outPubkey = outputRaw[2].split("SIG(")[1].replace(')','') if re.search("Comment:", line): commentRaw = line.split(': ', 1)[1] if issuerRaw != self.issuer or int(outAmount) != self.amount or outPubkey != self.recipient or commentRaw != self.comment: sys.stderr.write(colored("Le document généré est corrompu !\nNe fait plus confiance au noeud " + node + "\n", 'red')) sys.stderr.write(colored(issuerRaw + " envoi " + outAmount + " vers " + outPubkey + " with comment: " + commentRaw + "\n", "yellow")) sys.exit(1) else: print("Le document généré est conforme.") return self.txDoc def signDoc(self): # Sign TX document signature = fmt["64"](sign(self.txDoc.encode(), get_privkey(dunikey, "pubsec"))[:-len(self.txDoc.encode())]) self.signedDoc = self.txDoc + signature.decode() return self.signedDoc def sendTXDoc(self): # Build TX document querySign = gql( """ mutation ($signedDoc: String!){ tx( rawTx: $signedDoc ) { version issuers outputs } } """ ) paramsSign = { "signedDoc": self.signedDoc } # Send TX Signed document try: client.execute(querySign, variable_values=paramsSign) print(colored("Transaction effectué avec succès !", "green")) except Exception as e: message = ast.literal_eval(str(e))["message"] sys.stderr.write("Echec de la transaction:\n" + message + "\n") sys.exit(1) def send(self): self.genDoc() self.checkTXDoc() self.signDoc() self.sendTXDoc()