I was exploring steem and it pained me that there are no Perl bindings to interact with steem. So I made it my quest to implement a perl module wich would allow the comunity to write applications in Perl to interact with steem.
It all started with some tutorials wher i explained Howto write a steemit client in perl and i want to come back to them. Unfortunately, i quickly realized that when it comes to transaction signing there were some hurdles to overcome since perl was lacking some basic suport methods when it comes to ECDSA functionality.
Diverging from the original howtos I made the existing code into a perl module on CPAN and then came the hard part of:
there were already some packages which did the job but wither they were based in the fickr-base58 or they were using Math::GMPz instead of Math::BigInt so i wrote a new module Steemit::Base58 class for handeling this task.
The interface is rather simple:
use Steemit::Base58;
my $binary = Steemit::Base58::decode_base58( $base58_string );
my $base58 = Steemit::Base58::encode_base58( $binary );
this was needed in order to read out the Wallet import format used originally by bitcoin, which is also used in steem.
So far so good but this was actually still the easy part. Next we needed some elliptic curve cryptography things for signing and key transformations.
There are already a new ECDSA modules up on cpan but all were lacking the functionality and code quality that was needed in order to implement all required features. Luckily there was one package Math::EllipticCurve::Prime::Point hat already handles the basic elliptic curve arithmetic well. So only the functionality on top had to be developed.
This brougt then to light the Steemit::ECDSA package. It currently supports the following methods:
sub ecdsa_sign;
sub is_signature_canonical_canonical;
sub bytes_32_sha256;
sub ecdsa_verify;
sub calcPubKeyRecoveryParam;
sub recoverPubKey;
sub get_compressed_public_key;
sub get_recovery_factor;
sub point_from_x;
sub recover_y;
sub get_public_key_point;
They were all needed in order to generate a valid signature for a transaction and broadcast it to steemd node. Currently this is all bundeled up under.
Finally it had to be bgought together in the Steemit::WsClient package. This is the main module of the distribution wich should then be used to write applications.
An example would be:
use Modern::Perl;
use FindBin;
use lib "$FindBin::Bin/perlSteemit/lib/";
use Steemit::WsClient;
my $steem = Steemit::WsClient->new( posting_key => '' );
my $discussions = $steem->get_discussions_by_created({
tag => 'utopian-io',
limit => 1,
truncate_body => 1,
});
my $discussion = pop @$discussions;
$steem->vote( $discussion );
it can also be used for data extraction like calculating the average reputation of the authors of the last utopian posts:
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 );
Currently the basic functionality is there but now comes the time for further improvements.