Example #1
0
class OnChain(PaymentBase):

    """Making a payment on the bitcoin blockchain."""

    lock = threading.Lock()
    http_payment_data = 'Bitcoin-Transaction'
    http_402_price = 'Price'
    http_402_address = 'Bitcoin-Address'
    DUST_LIMIT = 3000  # dust limit in satoshi

    def __init__(self, wallet, db=None, db_dir=None):
        """Initialize payment handling for on-chain payments."""
        self.db = db or OnChainSQLite3(db_dir=db_dir)
        self.address = wallet.get_payout_address()
        self.provider = TwentyOneProvider(two1.TWO1_PROVIDER_HOST)

    @property
    def payment_headers(self):
        """List of headers to use for payment processing."""
        return [OnChain.http_payment_data]

    def get_402_headers(self, price, **kwargs):
        """Dict of headers to return in the initial 402 response."""
        return {OnChain.http_402_price: price,
                OnChain.http_402_address: kwargs.get('address', self.address)}

    def redeem_payment(self, price, request_headers, **kwargs):
        """Validate the transaction and broadcast it to the blockchain."""
        raw_tx = request_headers[OnChain.http_payment_data]
        logger.debug('[BitServ] Receieved transaction: {}'.format(raw_tx))

        # verify txn is above dust limit
        if price < OnChain.DUST_LIMIT:
            raise PaymentBelowDustLimitError(
                'Payment amount is below dust limit ({} Satoshi)'.format(OnChain.DUST_LIMIT))

        try:
            payment_tx = Transaction.from_hex(raw_tx)
        except:
            raise InvalidPaymentParameterError('Invalid transaction hex.')

        # Find the output with the merchant's address
        payment_index = payment_tx.output_index_for_address(kwargs.get('address', self.address))
        if payment_index is None:
            raise InvalidPaymentParameterError('Not paid to merchant.')

        # Verify that the payment is made for the correct amount
        if payment_tx.outputs[payment_index].value != price:
            raise InsufficientPaymentError('Incorrect payment amount.')

        # Synchronize the next block of code to manage its atomicity
        with self.lock:
            # Verify that we haven't seen this transaction before
            if self.db.lookup(str(payment_tx.hash)):
                raise DuplicatePaymentError('Payment already used.')
            else:
                self.db.create(str(payment_tx.hash), price)

            try:
                # Broadcast payment to network
                txid = self.provider.broadcast_transaction(raw_tx)
                logger.debug('[BitServ] Broadcasted: ' + txid)
            except Exception as e:
                # Roll back the database entry if the broadcast fails
                self.db.delete(str(payment_tx.hash))
                raise TransactionBroadcastError(str(e))

        return True
Example #2
0
class OnChain(PaymentBase):
    """Making a payment on the bitcoin blockchain."""

    lock = threading.Lock()
    http_payment_data = 'Bitcoin-Transaction'
    http_402_price = 'Price'
    http_402_address = 'Bitcoin-Address'
    DUST_LIMIT = 3000  # dust limit in satoshi

    def __init__(self, wallet, db=None, db_dir=None):
        """Initialize payment handling for on-chain payments."""
        self.db = db or OnChainSQLite3(db_dir=db_dir)
        self.address = wallet.get_payout_address()
        self.provider = TwentyOneProvider(two1.TWO1_PROVIDER_HOST)

    @property
    def payment_headers(self):
        """List of headers to use for payment processing."""
        return [OnChain.http_payment_data]

    def get_402_headers(self, price, **kwargs):
        """Dict of headers to return in the initial 402 response."""
        return {
            OnChain.http_402_price: price,
            OnChain.http_402_address: kwargs.get('address', self.address)
        }

    def redeem_payment(self, price, request_headers, **kwargs):
        """Validate the transaction and broadcast it to the blockchain."""
        raw_tx = request_headers[OnChain.http_payment_data]
        logger.debug('[BitServ] Receieved transaction: {}'.format(raw_tx))

        # verify txn is above dust limit
        if price < OnChain.DUST_LIMIT:
            raise PaymentBelowDustLimitError(
                'Payment amount is below dust limit ({} Satoshi)'.format(
                    OnChain.DUST_LIMIT))

        try:
            payment_tx = Transaction.from_hex(raw_tx)
        except:
            raise InvalidPaymentParameterError('Invalid transaction hex.')

        # Find the output with the merchant's address
        payment_index = payment_tx.output_index_for_address(
            kwargs.get('address', self.address))
        if payment_index is None:
            raise InvalidPaymentParameterError('Not paid to merchant.')

        # Verify that the payment is made for the correct amount
        if payment_tx.outputs[payment_index].value != price:
            raise InsufficientPaymentError('Incorrect payment amount.')

        # Synchronize the next block of code to manage its atomicity
        with self.lock:
            # Verify that we haven't seen this transaction before
            if self.db.lookup(str(payment_tx.hash)):
                raise DuplicatePaymentError('Payment already used.')
            else:
                self.db.create(str(payment_tx.hash), price)

            try:
                # Broadcast payment to network
                txid = self.provider.broadcast_transaction(raw_tx)
                logger.debug('[BitServ] Broadcasted: ' + txid)
            except Exception as e:
                # Roll back the database entry if the broadcast fails
                self.db.delete(str(payment_tx.hash))
                raise TransactionBroadcastError(str(e))

        return True
Example #3
0
    result = json.dumps({wallet_method: methodToCall()})
    print(result)


# Loop through methods
del sys.argv[0]
if sys.argv[0] == 'sign':
    pubkey = HDPublicKey.from_hex(sys.argv[1])
    server_privkey = wallet.get_private_for_public(pubkey)
    tx = Transaction.from_hex(sys.argv[2])
    script = Script.from_hex(sys.argv[3])

    for i, inp in enumerate(tx.inputs):
        tx.sign_input(i, Transaction.SIG_HASH_ALL, server_privkey, script)

    tx_id = provider.broadcast_transaction(tx.to_hex())

    print(json.dumps({'tx_id': tx_id, 'hex': tx.to_hex()}))
else:
    for arg in sys.argv:
        if arg == 'USD':
            rate = Price(wallet.balance())._get_usd_rate()
            print(rate)
        elif ':' in arg:
            address = arg.split(':')[1].strip()
            btc_amount = float(arg.split(':')[2].strip())
            sat_amount = convert_to_satoshis(btc_amount)
            txs = wallet.send_to(address, sat_amount)
            tx = txs[0]
            obj = {}
            obj['txid'] = tx['txid']