Business-Bitcoin

 view release on metacpan or  search on metacpan

lib/Business/Bitcoin/Request.pm  view on Meta::CPAN

# -*-cperl-*-
#
# Business::Bitcoin::Request - Bitcoin payment request
# Copyright (c) Ashish Gulhati <biz-btc at hash dot neomailbox.ch>
#
# $Id: lib/Business/Bitcoin/Request.pm v1.051 Tue Oct 16 22:26:58 PDT 2018 $

use warnings;
use strict;

package Business::Bitcoin::Request;

use DBI;
use LWP::UserAgent;
use HTTP::Request;
use Math::EllipticCurve::Prime;
use Math::EllipticCurve::Prime::Point;
use Digest::SHA qw(sha256 sha256_hex hmac_sha512_hex);
use Encode::Base58::BigInt;
use Crypt::RIPEMD160;

use vars qw( $VERSION $AUTOLOAD );

our ( $VERSION ) = '$Revision: 1.051 $' =~ /\s+([\d\.]+)/;

sub new {
  my ($class, %args) = @_;
  return undef if $args{Amount} !~ /^\d+$/; return undef if $args{StartIndex} and $args{StartIndex} =~ /\D/;
  my $db = $args{_BizBTC}->db; my $xpub = $args{_BizBTC}->xpub;
  my $timestamp = time;
  my $index = defined $args{StartIndex} ? $args{StartIndex} : 'NULL';
  my $refid = defined $args{Reference} ? "'$args{Reference}'" : 'NULL';
  return undef unless $db->do("INSERT INTO requests values ($index, '$args{Amount}', NULL, $refid, '$timestamp', NULL, NULL);");
  $index = $db->last_insert_id('%', '%', 'requests', 'reqid');
  $ENV{PATH} = undef;
  return undef unless my $address = _getaddress($args{_BizBTC}, $index);
  my $rows = $db->do("UPDATE requests set address='$address' where reqid='$index';");
  bless { Address => $address,
	  ID => $index,
	  Amount => $args{Amount},
	  DB => $db,
	  Reference => $args{Reference},
	  Confirmations => defined $args{Confirmations} ? $args{Confirmations} : 5,
	  Created => $timestamp }, $class;
}

sub verify {
  my $self = shift;
  my $ua = new LWP::UserAgent;
  my $req = HTTP::Request->new(GET => 'https://blockchain.info/q/addressbalance/' . $self->address . '?confirmations=' . $self->confirmations);
  my $res = $ua->request($req);
  my $paid = $res->content;
  $self->error($paid), return if $paid =~ /\D/;
  $self->error('');
  $paid >= $self->amount ? $paid : 0;
}

sub _find {
  my ($class, %args) = @_;
  return unless defined $args{Address} or defined $args{Reference};
  return if defined $args{Address} and defined $args{Reference};
  return unless defined $args{_BizBTC} and $args{_BizBTC}->db->ping;

  my $query = 'SELECT reqid,address,amount,reference,created,processed,status from requests WHERE ' .
    (defined $args{Address} ? "address='$args{Address}';" : "reference='$args{Reference}';");
  my ($reqid, $address, $amount, $refid, $created, $processed, $status) = $args{_BizBTC}->db->selectrow_array($query);
  bless { Address => $address,
	  Amount => $amount,
	  Reference => $refid,
	  ID => $reqid,
	  DB => $args{_BizBTC}->db,,
	  Confirmations => defined $args{Confirmations} ? $args{Confirmations} : 5,
	  Created => $created,
	  Processed => $processed,
	  Status => $status
	}, $class;
}

sub commit {
  my $self = shift;
  my $processed = $self->processed;
  my $status = $self->status;
  my $amount = $self->amount;
  my $refid = $self->reference;
  my $address = $self->address;
  my @updates;
  push @updates, "processed = '" . $processed . "'" if $processed;
  push @updates, "reference = '" . $refid . "'" if $refid;
  push @updates, "status = '" . $status . "'" if $status;
  push @updates, "amount = '" . $amount . "'" if $amount;
  return 1 unless my $updates = join ',',@updates;
  return undef unless $self->db->do("UPDATE requests SET $updates where address='$address';");
  return 1;
}

sub _getaddress {
  my ($bizbtc, $index) = @_;
  my $xpub = $bizbtc->xpub;
  my $curve = Math::EllipticCurve::Prime->from_name('secp256k1');
  my $xpubdata =  Math::BigInt->new(_decode58($xpub))->as_hex;
  $xpubdata =~ /.(.{8})(..)(.{8})(.{8})(.{64})(.{66})(.*)/;
  my ($ver, $depth, $fp, $i, $c, $Kc) = ($1, $2, $3, $4, $5, $6);
  my $K = Math::EllipticCurve::Prime::Point->from_hex(_decompress($Kc));
  if ($bizbtc->path eq 'electrum') {
    # m/0
    my ($Ki, $ci) = _CKDpub($K, $c, 0);
    # m/0/$index
    my ($Ki2, $ci2) = _CKDpub($Ki, $ci, $index);
    return _address(_compress($Ki2));
  }



( run in 0.524 second using v1.01-cache-2.11-cpan-39bf76dae61 )