Steemit-WsClient
view release on metacpan or search on metacpan
lib/Steemit/WsClient.pm view on Meta::CPAN
our $VERSION = '0.11';
=head1 SYNOPSIS
use Steemit::WsClient;
my $foo = Steemit::WsClient->new();
my $steem = Steemit::WsClient->new( url => 'https://some.steemit.d.node.address');
say "Initialized Steemit::WsClient client with url ".$steem->url;
#get the last 99 discussions with the tag utopian-io
#truncate the body since we dont care here
my $discussions = $steem->get_discussions_by_created({
tag => 'utopian-io',
limit => 99,
truncate_body => 100,
});
#extract the author names out of the result
my @author_names = map { $_->{author} } @$discussions;
say "last 99 authors: ".join(", ", @author_names);
#load the author details
my $authors = $steem->get_accounts( [@author_names] );
#say Dumper $authors->[0];
#calculate the reputation average
my $reputation_sum = 0;
for my $author ( @$authors ){
$reputation_sum += int( $author->{reputation} / 1000_000_000 );
}
say "Average reputation of the last 99 utopian authors: ". ( int( $reputation_sum / scalar(@$authors) ) / 100 );
=head1 DEPENDENCIES
you will need some packages.
openssl support for https
libgmp-dev for large integer aritmetic needd for the eliptical curve calculations
libssl-dev zlib1g-dev libgmp-dev
=head1 SUBROUTINES/METHODS
=cut
use Modern::Perl;
use Mojo::Base -base;
use Mojo::UserAgent;
use Mojo::JSON qw(decode_json encode_json);
use Data::Dumper;
has url => 'https://api.steemit.com/';
has ua => sub { Mojo::UserAgent->new };
has posting_key => undef;
has plain_posting_key => \&_transform_private_key;
=head2 all database api methods of the steemit api
L<https://github.com/steemit/steem/blob/master/libraries/app/database_api.cpp>
get_miner_queue
lookup_account_names
get_discussions
get_discussions_by_blog
get_witness_schedule
get_open_orders
get_trending_tags
lookup_witness_accounts
get_discussions_by_children
get_accounts
get_savings_withdraw_to
get_potential_signatures
get_required_signatures
get_order_book
get_key_references
get_tags_used_by_author
get_account_bandwidth
get_replies_by_last_update
get_dynamic_global_properties
get_block
get_witnesses
get_transaction_hex
get_comment_discussions_by_payout
get_discussions_by_votes
get_witness_by_account
verify_authority
get_config
get_account_votes
get_discussions_by_promoted
get_conversion_requests
get_account_history
get_escrow
get_discussions_by_comments
get_feed_history
get_hardfork_version
set_block_applied_callback
get_discussions_by_author_before_date
get_discussions_by_hot
get_discussions_by_payout
get_discussions_by_trending
get_recovery_request
get_reward_fund
get_chain_properties
get_witnesses_by_vote
get_account_references
get_post_discussions_by_payout
get_active_witnesses
get_ops_in_block
get_discussions_by_created
get_discussions_by_active
get_account_count
get_owner_history
get_next_scheduled_hardfork
get_savings_withdraw_from
lib/Steemit/WsClient.pm view on Meta::CPAN
return $self->_broadcast_transaction($operation);
}
=head2 delete_comment
$steem->delete_comment(
author => $author,
permlink => $permlink
)
you need the permlink
author will be filled with the user of your posting key if missing
=cut
sub delete_comment {
my( $self, %params ) = @_;
my $permlink = $params{permlink} or die "permlink missing for comment";
my $author = $params{author} // $self->get_key_references([$self->public_posting_key])->[0][0];
my $operation = [
delete_comment => {
"author" => $author,
"permlink" => $permlink,
}
];
return $self->_broadcast_transaction($operation);
}
sub _broadcast_transaction {
my( $self, @operations ) = @_;
my $properties = $self->get_dynamic_global_properties();
my $block_number = $properties->{last_irreversible_block_num};
my $block_details = $self->get_block( $block_number );
my $ref_block_id = $block_details->{previous},
my $time = $properties->{time};
#my $expiration = "2018-02-24T17:00:51";#TODO dynamic date
my ($year,$month,$day, $hour,$min,$sec) = split /\D/, $time;
require Date::Calc;
my $epoch = Date::Calc::Date_to_Time($year,$month,$day, $hour,$min,$sec);
($year,$month,$day, $hour,$min,$sec) = Date::Calc::Time_to_Date($epoch + 600 );
my $expiration = "$year-$month-$day".'T'."$hour:$min:$sec";
my $transaction = {
ref_block_num => ( $block_number - 1 )& 0xffff,
ref_block_prefix => unpack( "xxxxV", pack('H*',$ref_block_id)),
expiration => $expiration,
operations => [@operations],
extensions => [],
signatures => [],
};
my $serialized_transaction = $self->_serialize_transaction_message( $transaction );
my $bin_private_key = $self->plain_posting_key;
require Steemit::ECDSA;
my ( $r, $s, $i ) = Steemit::ECDSA::ecdsa_sign( $serialized_transaction, Math::BigInt->from_bytes( $bin_private_key ) );
$i += 4;
$i += 27;
my $signature = join('', map { unpack 'H*', $_ } ( pack("C", $i ), map { $_->as_bytes} ($r,$s )) );
unless( Steemit::ECDSA::is_signature_canonical_canonical( pack "H*", $signature ) ){
die "signature $signature is not canonical";
}
$transaction->{signatures} = [ $signature ];
$self->_request('network_broadcast_api','broadcast_transaction_synchronous',$transaction);
}
sub public_posting_key {
my( $self ) = @_;
unless( $self->{public_posting_key} ){
require Steemit::ECDSA;
my $bin_pubkey = Steemit::ECDSA::get_compressed_public_key( Math::BigInt->from_bytes( $self->plain_posting_key ) );
#TODO use the STM from dynamic lookup in get_config or somewhere
require Crypt::RIPEMD160;
my $rip = Crypt::RIPEMD160->new;
$rip->reset;
$rip->add($bin_pubkey);
my $checksum = $rip->digest;
$rip->reset;
$rip->add('');
$self->{public_posting_key} = "STM".Steemit::Base58::encode_base58($bin_pubkey.substr($checksum,0,4));
}
return $self->{public_posting_key}
}
sub _transform_private_key {
my( $self ) = @_;
die "posting_key missing" unless( $self->posting_key );
my $base58 = $self->posting_key;
require Steemit::Base58;
my $binary = Steemit::Base58::decode_base58( $base58 );
my $version = substr( $binary, 0, 1 );
my $binary_private_key = substr( $binary, 1, -4);
my $checksum = substr( $binary, -4);
die "invalid version in wif ( 0x80 needed ) " unless $version eq pack "H*", '80';
require Digest::SHA;
my $generated_checksum = substr( Digest::SHA::sha256( Digest::SHA::sha256( $version.$binary_private_key )), 0, 4 );
die "invalid checksum " unless $generated_checksum eq $checksum;
return $binary_private_key;
}
sub _serialize_transaction_message {
my ($self,$transaction) = @_;
my $serialized_transaction;
$serialized_transaction .= pack 'v', $transaction->{ref_block_num};
$serialized_transaction .= pack 'V', $transaction->{ref_block_prefix};
require Date::Calc;
#2016-08-08T12:24:17
my @dates = split /\D/, $transaction->{expiration} ;
my $epoch = Date::Calc::Date_to_Time( @dates);
$serialized_transaction .= pack 'L', $epoch;
$serialized_transaction .= pack "C", scalar( @{ $transaction->{operations} });
require Steemit::OperationSerializer;
my $op_ser = Steemit::OperationSerializer->new;
for my $operation ( @{ $transaction->{operations} } ) {
my ($operation_name,$operations_parameters) = @$operation;
$serialized_transaction .= $op_ser->serialize_operation(
$operation_name,
$operations_parameters,
);
}
#extentions in case we realy need them at some point we will have to implement this is a less nive way ;)
die "extentions not supported" if $transaction->{extensions} and $transaction->{extensions}[0];
$serialized_transaction .= pack 'H*', '00';
return pack( 'H*', ( '0' x 64 )).$serialized_transaction;
}
=head1 REPOSITORY
L<https://github.com/snkoehn/perlSteemit>
=head1 AUTHOR
snkoehn, C<< <snkoehn at cpan.org> >>
=head1 BUGS
Please report any bugs or feature requests to C<bug-steemit at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Steemit::WsClient>. I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.
( run in 2.033 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )