def valid_xpub(xpub): from helpers.configurationhelpers import get_use_testnet testnet = get_use_testnet() if testnet is True: return isinstance(xpub, str) and xpub[:4] == "tpub" else: return isinstance(xpub, str) and xpub[:4] == "xpub"
def test_verify_message_with_testnet_address(self): if get_use_testnet() is False: print('Change configuration to use testnet to test this!!') return address = 'n2xqSGhqeQqiC6rp34NmPF8xmjQrcxLc6K' message = 'This is a test message for verification of n2xq' signature = 'H4NTp6Z3RWVndpmapw3sJ/CZd0jDS0evgQxasAN+hn3KGhoMLNvzs1Ms3nvPAqdf04XG3O6A4QmmIi70y14Lh18=' assert verify_message(address=address, message=message, signature=signature)
def valid_address(address): if not isinstance(address, str): return False from helpers.configurationhelpers import get_use_testnet testnet = get_use_testnet() if testnet is True: return re.match(TESTNET_ADDRESS_REGEX, address) is not None or valid_bech32_address(address) else: return re.match(MAINNET_ADDRESS_REGEX, address) is not None or valid_bech32_address(address)
def add_key(): wallet = load_wallet() try: address = privkey_to_address( args.private_key, magicbyte=0 if get_use_testnet() is False else 111) except AssertionError: print('Invalid private key: %s' % args.private_key, file=sys.stderr) sys.exit(1) new_key = {address: args.private_key} wallet.update(new_key) save_wallet(wallet)
def get_recommended_fee_blockcypher(): url = 'https://api.blockcypher.com/v1/btc/test3' if get_use_testnet( ) is True else 'https://api.blockcypher.com/v1/btc/main' try: LOG.info('GET %s' % url) r = requests.get(url=url) data = r.json() except Exception as ex: raise Exception('Unable get recommended fee from blockcypher.com: %s' % ex) return { 'high_priority': data['high_fee_per_kb'], 'low_priority': data['low_fee_per_kb'], 'medium_priority': data['medium_fee_per_kb'] }
def valid_bech32_address(address): if not isinstance(address, str): return False hrp, data = bech32_decode(address) if (hrp, data) == (None, None): return False from helpers.configurationhelpers import get_use_testnet testnet = get_use_testnet() if testnet is True: return re.match(LOWERCASE_TESTNET_BECH32_ADDRESS_REGEX, address) is not None or re.match( UPPERCASE_TESTNET_BECH32_ADDRESS_REGEX, address) is not None else: return re.match(LOWERCASE_MAINNET_BECH32_ADDRESS_REGEX, address) is not None or re.match( UPPERCASE_MAINNET_BECH32_ADDRESS_REGEX, address) is not None
#!/usr/bin/env python # -*- coding: utf-8 -*- import bitcoin from bitcoin.wallet import CBitcoinSecret from bitcoin.signmessage import BitcoinMessage, VerifyMessage, SignMessage from helpers.configurationhelpers import get_use_testnet bitcoin.SelectParams( name='testnet' if get_use_testnet() is True else 'mainnet') def sign_message(message, private_key): key = CBitcoinSecret(private_key) return SignMessage(key=key, message=BitcoinMessage(message)).decode() def verify_message(address, message, signature): try: return VerifyMessage(address=address, message=BitcoinMessage(message), sig=signature) except Exception as ex: return False def sign_and_verify(private_key, message, address): key = CBitcoinSecret(private_key) signature = SignMessage(key=key, message=BitcoinMessage(message)) assert VerifyMessage(address=address, message=BitcoinMessage(message),
def run(self): LOG.info('Running Spellbook Script: %s' % os.path.splitext(os.path.basename(__file__))[0]) if self.json is not None: if 'seller_id' not in self.json: LOG.error( 'Payment request json does not contain the seller id') return if 'amount_fiat' not in self.json: LOG.error( 'Payment request json does not contain the fiat amount!') return if 'currency' not in self.json: LOG.error( 'Payment request json does not contain the fiat currency!') return elif self.json['currency'] not in ['EUR', 'USD']: LOG.error( 'Payment processor currently only supports EUR or USD as currency!' ) return # Create a new payment request payment_request = PaymentRequest() payment_request.seller_id = self.json['seller_id'] payment_request.amount_fiat = self.json['amount_fiat'] payment_request.currency = self.json['currency'] payment_request.note = self.json[ 'note'] if 'note' in self.json else None # Use the number of times the trigger has been triggered as the index in the hot wallet account payment_request.address = get_address_from_wallet( account=ACCOUNT, index=self.triggered) # Get the current BTC price from bitcoinaverage url = 'https://apiv2.bitcoinaverage.com/indices/global/ticker/BTC{currency}'.format( currency=payment_request.currency) LOG.info('Retrieving BTC%s price from bitcoinaverage.com' % payment_request.currency) LOG.info('GET %s' % url) try: r = requests.get(url=url) price_data = r.json() except Exception as ex: LOG.error( 'Unable to retrieve BTC price from bitcoinaverage.com: %s' % ex) self.http_response = { 'error': 'Unable to convert %s amount to BTC amount' % payment_request.currency } return payment_request.price_btc = price_data['last'] payment_request.price_timestamp = price_data['timestamp'] if payment_request.price_btc == 0: LOG.error('BTC price can not be 0!') self.http_response = { 'error': 'Unable to convert %s amount to BTC amount' % payment_request.currency } return payment_request.amount_btc = int(payment_request.amount_fiat / payment_request.price_btc * 1e8) LOG.info('Created new payment request: %s' % payment_request.payment_request_id) LOG.info('Fiat Amount: %s %s' % (payment_request.amount_fiat, payment_request.currency)) LOG.info('BTC Amount: %s (price %s %s/BTC @ %s)' % (payment_request.amount_btc, payment_request.price_btc, payment_request.currency, datetime.fromtimestamp(payment_request.price_timestamp ).strftime('%Y-%m-%d %H:%M:%S'))) LOG.info('Note: %s' % payment_request.note) LOG.info('Address: %s' % payment_request.address) payment_request.save() # Set the HTTP response with the payment request details self.http_response = payment_request.json_encodable() # Create a trigger to monitor the balance of the address (This is a fallback in case the listener doesn't pick up the transaction) # The script will then check the number of confirmations of the transaction if one is received trigger = get_trigger( trigger_id=payment_request.payment_request_id, trigger_type=TriggerType.BALANCE) trigger.address = payment_request.address trigger.amount = payment_request.amount_btc trigger.script = os.path.join('PaymentProcessor', 'PaymentProcessorPaymentStatus.py') trigger.data = { 'payment_request_id': payment_request.payment_request_id } trigger.self_destruct = int(time.time()) + REQUEST_TIMEOUT trigger.status = 'Active' trigger.multi = True trigger.save() # Spawn up a separate process to listen for the payment transaction url = 'http://%s:%s/spellbook/triggers/PaymentProcessorTransactionReceived/post' % ( get_host(), get_port()) notify_program = os.path.join('helpers', 'notify_transaction.py') command = r'%s %s %s #txid#' % (notify_program, url, payment_request.payment_request_id) # Construct the command for the listener so that it listens for any receiving transactions on the address and executes the notify_transaction program when # a transaction is detected and stop the listener if no tx happens within the timeout period. listener_program = os.path.join('listeners', 'transaction_listener.py') run_command = r'%s --address=%s --timeout=%s --exit --receive --command="%s"' % ( listener_program, payment_request.address, LISTENER_TIMEOUT, command) # If we are configured for testnet we must also add the --testnet flag to the listener if get_use_testnet(): run_command += ' --testnet' action = get_action(action_id='start_listener', action_type=ActionType.SPAWNPROCESS) action.run_command = run_command # Run the action immediately instead of saving it, so we are not creating new actions with each request action.run()
#!/usr/bin/env python # -*- coding: utf-8 -*- from binascii import hexlify, unhexlify from .BIP32 import bip32_ckd, bip32_extract_key, MAGICBYTE, bip32_master_key, VERSION_BYTES, bip32_privtopub from .BIP39 import get_seed from helpers.publickeyhelpers import encode_pubkey, pubkey_to_address from helpers.privatekeyhelpers import encode_privkey, privkey_to_address from helpers.configurationhelpers import get_use_testnet HARDENED = 2**31 COIN_TYPE = 1 if get_use_testnet() is True else 0 def get_address_from_xpub(xpub, i): """ Get a Bitcoin address from an xpub key :param xpub: The xpub key :param i: The index of the address :return: A Bitcoin Address """ pub0 = bip32_ckd(xpub, 0) public_key = bip32_ckd(pub0, i) hex_key = encode_pubkey(bip32_extract_key(public_key), 'hex_compressed') address = pubkey_to_address(hex_key, magicbyte=MAGICBYTE) return address def get_addresses_from_xpub(xpub, i=100):
from helpers.privatekeyhelpers import privkey_to_pubkey, add_privkeys from helpers.publickeyhelpers import add_pubkeys, compress, bin_hash160, encode_pubkey, pubkey_to_address from helpers.configurationhelpers import get_use_testnet BIP32_DERIVATION_PATH_REGEX = "^m(\/\d+'?)*" HARDENED = 2**31 MAINNET_PRIVATE = b'\x04\x88\xAD\xE4' MAINNET_PUBLIC = b'\x04\x88\xB2\x1E' TESTNET_PRIVATE = b'\x04\x35\x83\x94' TESTNET_PUBLIC = b'\x04\x35\x87\xCF' PRIVATE = [MAINNET_PRIVATE, TESTNET_PRIVATE] PUBLIC = [MAINNET_PUBLIC, TESTNET_PUBLIC] VERSION_BYTES = TESTNET_PRIVATE if get_use_testnet( ) is True else MAINNET_PRIVATE MAGICBYTE = 111 if get_use_testnet() is True else 0 def set_chain_mode(mainnet=True): """ Override the configuration to switch between mainnet and testnet mode :param mainnet: True or False """ global VERSION_BYTES, MAGICBYTE VERSION_BYTES = MAINNET_PRIVATE if mainnet is True else TESTNET_PRIVATE MAGICBYTE = 0 if mainnet is True else 111 # Set the chain mode based on the current configuration
def teardown_module(module): """ teardown any state that was previously setup with a setup_module method.""" set_chain_mode(mainnet=(get_use_testnet() is False))