def add_user(): """ Register a new User. Create a User and a UserKey based on the JWS header and payload. --- operationId: addUser parameters: - name: user in: body description: A new User to add required: true schema: $ref: '#/definitions/User' responses: '200': description: "user's new key" schema: $ref: '#/definitions/UserKey' default: description: unexpected error schema: $ref: '#/definitions/errorModel' security: - kid: [] - typ: [] - alg: [] """ load_jws_from_request(request) if not hasattr(request, 'jws_header') or request.jws_header is None: return "Invalid Payload", 401 username = request.jws_payload['data'].get('username') address = request.jws_header['kid'] user = SLM_User(username=username) ses.add(user) try: ses.commit() except Exception as ie: current_app.logger.exception(ie) ses.rollback() ses.flush() return 'username taken', 400 userkey = UserKey(key=address, keytype='public', user_id=user.id, last_nonce=request.jws_payload['iat']*1000) ses.add(userkey) for plug in ps: ses.add(models.Balance(total=0, available=0, currency=ps[plug].CURRENCY, reference='open account', user_id=user.id)) try: ses.commit() except Exception as ie: current_app.logger.exception(ie) ses.rollback() ses.flush() #ses.delete(user) #ses.commit() return 'username taken', 400 jresult = jsonify2(userkey, 'UserKey') current_app.logger.info("registered user %s with key %s" % (user.id, userkey.key)) return current_app.bitjws.create_response(jresult)
def main(sys_args=sys.argv[1:]): """ The main CLI entry point. Reads the command line arguments which should be filled in by the calling wallet node. Handler for walletnotify and blocknotify. """ global lastblock client = create_client() parser = argparse.ArgumentParser() parser.add_argument("type") parser.add_argument("data") args = parser.parse_args(sys_args) typ = args.type if typ == 'transaction' and args.data is not None: txid = args.data txd = client.gettransaction(txid) confirmed = txd['confirmations'] >= CONFS for p, put in enumerate(txd['details']): if put['category'] == 'send': confirm_send(put['address'], put['amount'], ref_id="%s:%s" % (txid, p)) elif put['category'] == 'receive': process_receive("%s:%s" % (txid, p), put, confirmed) elif typ == 'block': info = client.getinfo() if info['blocks'] <= lastblock: return lastblock = info['blocks'] creds = ses.query(models.Credit)\ .filter(models.Credit.state == 'unconfirmed')\ .filter(models.Credit.network == NETWORK) for cred in creds: txid = cred.ref_id.split(':')[0] or cred.ref_id txd = client.gettransaction(txid) if txd['confirmations'] >= CONFS: cred.state = 'complete' for p, put in enumerate(txd['details']): cred.ref_id = "%s:%s" % (txd['txid'], p) ses.add(cred) try: ses.commit() except Exception as e: logger.exception(e) ses.rollback() ses.flush() # update balances total = int(float(client.getbalance("*", 0)) * 1e8) avail = int(float(info['balance']) * 1e8) hwb = models.HWBalance(avail, total, CURRENCIES[0], NETWORK.lower()) ses.add(hwb) try: ses.commit() except Exception as ie: ses.rollback() ses.flush()
def __init__(self): for cur in json.loads(CFG.get('internal', 'CURRENCIES')): #TODO set this to maximum transaction sizes for each currency hwb = models.HWBalance(100000000000, 100000000000, cur, 'internal') ses.add(hwb) try: ses.commit() except Exception as ie: ses.rollback() ses.flush()
def create_address(): """ Create a new address owned by your user. --- parameters: - name: address in: body description: The pseudo-address you would like to create. i.e. currency and network required: true schema: $ref: '#/definitions/Address' responses: '200': description: Your new address schema: $ref: '#/definitions/Address' default: description: unexpected error schema: $ref: '#/definitions/errorModel' security: - kid: [] - typ: [] - alg: [] operationId: createAddress """ currency = request.jws_payload['data'].get('currency') network = request.jws_payload['data'].get('network') state = 'active' if network.lower() in ps: try: addy = ps[network.lower()].get_new_address() except Exception as e: print type(e) print e current_app.logger.error(e) return 'wallet temporarily unavailable', 500 else: return 'Invalid network', 400 address = wm.Address(addy, currency, network, state, current_user.id) ses.add(address) try: ses.commit() except Exception as ie: ses.rollback() ses.flush() return 'Could not save address', 500 newaddy = json.loads(jsonify2(address, 'Address')) current_app.logger.info("created new address %s" % newaddy) ses.close() return current_app.bitjws.create_response(newaddy)
def create_debit(): """ Create a new debit, sending tokens out of your User's account. --- parameters: - name: debit in: body description: The debit you would like to create. required: true schema: $ref: '#/definitions/Debit' responses: '200': description: The Debit record schema: $ref: '#/definitions/Debit' default: description: unexpected error schema: $ref: '#/definitions/errorModel' security: - kid: [] - typ: [] - alg: [] operationId: sendMoney """ currency = request.jws_payload['data'].get('currency') amount = Amount("%s %s" % (request.jws_payload['data'].get('amount'), currency)) address = request.jws_payload['data'].get('address') network = request.jws_payload['data'].get('network') reference = request.jws_payload['data'].get('reference') state = 'unconfirmed' try: debit = plugin.create_debit(current_user, amount, currency, address, network, reference, state='unconfirmed', plugins=ps, session=ses) plugin.process_debit(debit, plugins=ps, session=ses) except (IOError, ValueError) as e: current_app.logger.exception(e) ses.rollback() ses.flush() return "Unable to send money", 400 except Exception as e: current_app.logger.exception(e) ses.rollback() ses.flush() return "Unable to send money", 500 result = json.loads(jsonify2(debit, 'Debit')) current_app.logger.info("created new debit %s" % result) ses.close() return current_app.bitjws.create_response(result)
def create_address(): """ Create a new address owned by your user. --- parameters: - name: address in: body description: The pseudo-address you would like to create. i.e. currency and network required: true schema: $ref: '#/definitions/Address' responses: '200': description: Your new address schema: $ref: '#/definitions/Address' default: description: unexpected error schema: $ref: '#/definitions/errorModel' security: - kid: [] - typ: [] - alg: [] operationId: createAddress """ currency = request.jws_payload['data'].get('currency') network = request.jws_payload['data'].get('network') state = 'active' if network.lower() in ps: try: addy = ps[network.lower()].get_new_address() except Exception as e: print type(e) print e current_app.logger.error(e) return 'wallet temporarily unavailable', 500 else: return 'Invalid network', 400 address = models.Address(addy, currency, network, state, current_user.id) ses.add(address) try: ses.commit() except Exception as ie: ses.rollback() ses.flush() return 'Could not save address', 500 newaddy = jsonify2(address, 'Address') current_app.logger.info("created new address %s" % newaddy) return current_app.bitjws.create_response(newaddy)
def adjust_hwbalance(available=None, total=None): if available is None and total is None: return hwb = ses.query(models.HWBalance).filter(models.HWBalance.network == NETWORK.lower()).order_by(models.HWBalance.time.desc()).first() if available is not None: hwb.available += available if total is not None: hwb.total += total ses.add(hwb) try: ses.commit() except Exception as e: logger.exception(e) ses.rollback() ses.flush()
def assign_address(address, user): dbaddy = ses.query(models.Address).filter(models.Address.address == address).first() if dbaddy is None: ses.add(models.Address(address, CURRENCY, NETWORK, 'active', user.id)) elif dbaddy.user_id != user.id: dbaddy.user_id = user.id ses.add(dbaddy) else: return creds = ses.query(models.Credit).filter(models.Credit.address == address) for c in creds: ses.delete(c) try: ses.commit() except Exception as ie: ses.rollback() ses.flush()
def add_user(): """ Register a new User. Create a User and a UserKey based on the JWS header and payload. --- operationId: addUser parameters: - name: user in: body description: A new User to add required: true schema: $ref: '#/definitions/User' responses: '200': description: "user's new key" schema: $ref: '#/definitions/UserKey' default: description: unexpected error schema: $ref: '#/definitions/errorModel' security: - kid: [] - typ: [] - alg: [] """ load_jws_from_request(request) if not hasattr(request, 'jws_header') or request.jws_header is None: return "Invalid Payload", 401 username = request.jws_payload['data'].get('username') address = request.jws_header['kid'] last_nonce = request.jws_payload['iat']*1000 try: user, userkey = create_user_and_key(username=username, address=address, last_nonce=last_nonce, session=ses) except IOError: ses.rollback() ses.flush() return 'username or key taken', 400 jresult = json.loads(jsonify2(userkey, 'UserKey')) current_app.logger.info("registered user %s with key %s" % (user.id, userkey.key)) ses.close() return current_app.bitjws.create_response(jresult)
def get_last_nonce(app, key, nonce): """ Get the last_nonce used by the given key from the SQLAlchemy database. Update the last_nonce to nonce at the same time. :param str key: the public key the nonce belongs to :param int nonce: the last nonce used by this key """ uk = ses.query(um.UserKey).filter(um.UserKey.key==key)\ .filter(um.UserKey.last_nonce<nonce * 1000).first() if not uk: return None lastnonce = copy.copy(uk.last_nonce) # TODO Update DB record in same query as above, if possible uk.last_nonce = nonce * 1000 try: ses.commit() except Exception as e: current_app.logger.exception(e) ses.rollback() ses.flush() return lastnonce
def get_last_nonce(app, key, nonce): """ Get the last_nonce used by the given key from the SQLAlchemy database. Update the last_nonce to nonce at the same time. :param str key: the public key the nonce belongs to :param int nonce: the last nonce used by this key """ uk = ses.query(UserKey).filter(UserKey.key==key)\ .filter(UserKey.last_nonce<nonce * 1000).first() if not uk: return None lastnonce = copy.copy(uk.last_nonce) # TODO Update DB record in same query as above, if possible uk.last_nonce = nonce * 1000 try: ses.commit() except Exception as e: current_app.logger.exception(e) ses.rollback() ses.flush() return lastnonce
def create_user(): privkey = bitjws.PrivateKey() my_pubkey = privkey.pubkey.serialize() my_address = bitjws.pubkey_to_addr(my_pubkey) username = str(my_address)[0:8] user = models.User(username=username) ses.add(user) try: ses.commit() except Exception as ie: print ie ses.rollback() ses.flush() userkey = models.UserKey(key=my_address, keytype='public', user_id=user.id, last_nonce=0) ses.add(userkey) ses.add(models.Balance(total=0, available=0, currency=CURRENCY, reference='open account', user_id=user.id)) try: ses.commit() except Exception as ie: print ie ses.rollback() ses.flush() return user
from desw import ses from sqlalchemy_models import wallet as wm hwb = wm.HWBalance(0, 0, 'DASH', 'dash') ses.add(hwb) try: ses.commit() except Exception as ie: ses.rollback() ses.flush()
def create_debit(): """ Create a new debit, sending tokens out of your User's account. --- parameters: - name: debit in: body description: The debit you would like to create. required: true schema: $ref: '#/definitions/Debit' responses: '200': description: The Debit record schema: $ref: '#/definitions/Debit' default: description: unexpected error schema: $ref: '#/definitions/errorModel' security: - kid: [] - typ: [] - alg: [] operationId: sendMoney """ amount = request.jws_payload['data'].get('amount') address = request.jws_payload['data'].get('address') currency = request.jws_payload['data'].get('currency') network = request.jws_payload['data'].get('network') reference = request.jws_payload['data'].get('reference') state = 'unconfirmed' if network.lower() not in ps: return 'Invalid network', 400 dbaddy = ses.query(models.Address)\ .filter(models.Address.address == address)\ .filter(models.Address.currency == currency).first() if dbaddy is not None and dbaddy.address == address: network = 'internal' elif network == 'internal' and dbaddy is None: return "internal address not found", 400 txid = 'TBD' debit = models.Debit(amount, address, currency, network, state, reference, txid, current_user.id) ses.add(debit) bal = ses.query(models.Balance)\ .filter(models.Balance.user_id == current_user.id)\ .filter(models.Balance.currency == currency)\ .order_by(models.Balance.time.desc()).first() if not bal or bal.available < amount: return "not enough funds", 400 else: bal.total -= amount bal.available -= amount ses.add(bal) current_app.logger.info("updating balance %s" % jsonify2(bal, 'Balance')) try: ses.commit() except Exception as ie: current_app.logger.exception(ie) ses.rollback() ses.flush() return "unable to send funds", 500 if network == 'internal': bal2 = ses.query(models.Balance)\ .filter(models.Balance.user_id == dbaddy.user_id)\ .filter(models.Balance.currency == currency)\ .order_by(models.Balance.time.desc()).first() bal2.available += amount bal2.total += amount credit = models.Credit(amount, address, currency, network, 'complete', reference, debit.id, dbaddy.user_id) ses.add(bal2) ses.add(credit) current_app.logger.info("updating balance %s" % jsonify2(bal2, 'Balance')) current_app.logger.info("created new credit %s" % jsonify2(credit, 'Credit')) try: ses.commit() debit.ref_id = str(credit.id) except Exception as ie: ses.rollback() ses.flush() return "unable to send funds", 500 else: try: debit.ref_id = ps[network.lower()].send_to_address(address, float(amount) / 1e8) except Exception as e: print type(e) print e current_app.logger.error(e) return 'wallet temporarily unavailable', 500 debit.state = 'complete' try: ses.commit() except Exception as ie: current_app.logger.exception(ie) ses.rollback() ses.flush() return "Sent but unconfirmed... check again soon", 200 result = jsonify2(debit, 'Debit') current_app.logger.info("created new debit %s" % result) return current_app.bitjws.create_response(result)
def add_user(): """ Register a new User. Create a User and a UserKey based on the JWS header and payload. --- operationId: addUser parameters: - name: user in: body description: A new User to add required: true schema: $ref: '#/definitions/User' responses: '200': description: "user's new key" schema: $ref: '#/definitions/UserKey' default: description: unexpected error schema: $ref: '#/definitions/errorModel' security: - kid: [] - typ: [] - alg: [] """ load_jws_from_request(request) if not hasattr(request, 'jws_header') or request.jws_header is None: return "Invalid Payload", 401 username = request.jws_payload['data'].get('username') address = request.jws_header['kid'] user = SLM_User(username=username) ses.add(user) try: ses.commit() except Exception as ie: current_app.logger.exception(ie) ses.rollback() ses.flush() return 'username taken', 400 userkey = UserKey(key=address, keytype='public', user_id=user.id, last_nonce=request.jws_payload['iat'] * 1000) ses.add(userkey) for cur in json.loads(CFG.get('internal', 'CURRENCIES')): ses.add( models.Balance(total=0, available=0, currency=cur, reference='open account', user_id=user.id)) try: ses.commit() except Exception as ie: current_app.logger.exception(ie) ses.rollback() ses.flush() #ses.delete(user) #ses.commit() return 'username taken', 400 jresult = jsonify2(userkey, 'UserKey') current_app.logger.info("registered user %s with key %s" % (user.id, userkey.key)) return current_app.bitjws.create_response(jresult)
def create_debit(): """ Create a new debit, sending tokens out of your User's account. --- parameters: - name: debit in: body description: The debit you would like to create. required: true schema: $ref: '#/definitions/Debit' responses: '200': description: The Debit record schema: $ref: '#/definitions/Debit' default: description: unexpected error schema: $ref: '#/definitions/errorModel' security: - kid: [] - typ: [] - alg: [] operationId: sendMoney """ amount = request.jws_payload['data'].get('amount') address = request.jws_payload['data'].get('address') currency = request.jws_payload['data'].get('currency') network = request.jws_payload['data'].get('network') reference = request.jws_payload['data'].get('reference') state = 'unconfirmed' if network.lower() not in ps: return 'Invalid network', 400 dbaddy = ses.query(models.Address)\ .filter(models.Address.address == address)\ .filter(models.Address.currency == currency).first() if dbaddy is not None and dbaddy.address == address: network = 'internal' elif network == 'internal' and dbaddy is None: return "internal address not found", 400 fee = int(CFG.get(network.lower(), 'FEE')) txid = 'TBD' debit = models.Debit(amount, fee, address, currency, network, state, reference, txid, current_user.id) ses.add(debit) bal = ses.query(models.Balance)\ .filter(models.Balance.user_id == current_user.id)\ .filter(models.Balance.currency == currency)\ .order_by(models.Balance.time.desc()).first() if not bal or bal.available < amount + fee: return "not enough funds", 400 else: bal.total -= amount + fee bal.available -= amount + fee ses.add(bal) current_app.logger.info("updating balance %s" % jsonify2(bal, 'Balance')) try: ses.commit() except Exception as ie: current_app.logger.exception(ie) ses.rollback() ses.flush() return "unable to send funds", 500 if network == 'internal': bal2 = ses.query(models.Balance)\ .filter(models.Balance.user_id == dbaddy.user_id)\ .filter(models.Balance.currency == currency)\ .order_by(models.Balance.time.desc()).first() bal2.available += amount bal2.total += amount credit = models.Credit(amount, address, currency, network, 'complete', reference, debit.id, dbaddy.user_id) ses.add(bal2) ses.add(credit) current_app.logger.info("updating balance %s" % jsonify2(bal2, 'Balance')) current_app.logger.info("created new credit %s" % jsonify2(credit, 'Credit')) try: ses.commit() debit.ref_id = str(credit.id) except Exception as ie: ses.rollback() ses.flush() return "unable to send funds", 500 else: try: debit.ref_id = ps[network.lower()].send_to_address( address, float(amount) / 1e8) except Exception as e: print type(e) print e current_app.logger.error(e) return 'wallet temporarily unavailable', 500 debit.state = 'complete' try: ses.commit() except Exception as ie: current_app.logger.exception(ie) ses.rollback() ses.flush() return "Sent but unconfirmed... check again soon", 200 result = jsonify2(debit, 'Debit') current_app.logger.info("created new debit %s" % result) return current_app.bitjws.create_response(result)
def main(sys_args=sys.argv[1:]): """ The main CLI entry point. Reads the command line arguments which should be filled in by the calling wallet node. Handler for walletnotify and blocknotify. """ global lastblock client = create_client() parser = argparse.ArgumentParser() parser.add_argument("type") parser.add_argument("data") args = parser.parse_args(sys_args) typ = args.type if typ == 'transaction' and args.data is not None: txid = args.data txd = client.gettransaction(txid) confirmed = txd['confirmations'] >= CONFS for p, put in enumerate(txd['details']): if put['category'] == 'send': try: confirm_send(put['address'], put['amount'], ref_id=txid) except ValueError as ve: logger.info(str(ve)) elif put['category'] == 'receive': try: process_receive(txid, put, confirmed) except ValueError as ve: logger.info(str(ve)) elif typ == 'block': info = client.getinfo() if info['blocks'] <= lastblock: return lastblock = info['blocks'] creds = ses.query(wm.Credit)\ .filter(wm.Credit.transaction_state == 'unconfirmed')\ .filter(wm.Credit.network == NETWORK) modified = False for cred in creds: txid = cred.ref_id.split(':')[0] or cred.ref_id txd = client.gettransaction(txid) if txd['confirmations'] >= CONFS or \ txd['bcconfirmations'] >= CONFS: cred.load_commodities() confirm_credit(credit=cred, txid=txd['txid'], session=ses) # cred.transaction_state = 'complete' # for p, put in enumerate(txd['details']): # cred.ref_id = "%s:%s" % (txd['txid'], p) # ses.add(cred) modified = True if modified: try: ses.commit() except Exception as e: logger.exception(e) ses.rollback() ses.flush() # update balances total = Amount("%s %s" % (client.getbalance("*", 0), CURRENCIES[0])) avail = Amount("%s %s" % (info['balance'], CURRENCIES[0])) hwb = wm.HWBalance(avail, total, CURRENCIES[0], NETWORK) ses.add(hwb) try: ses.commit() except Exception as ie: ses.rollback() ses.flush() ses.close()