File Coverage

blib/lib/Web3/Tiny/Util.pm
Criterion Covered Total %
statement 46 46 100.0
branch 12 22 54.5
condition 9 15 60.0
subroutine 9 9 100.0
pod 0 4 0.0
total 76 96 79.1


line stmt bran cond sub pod time code
1             package Web3::Tiny::Util;
2              
3 2     2   87783 use strict;
  2         17  
  2         73  
4 2     2   9 use warnings;
  2         4  
  2         77  
5 2     2   7 use Exporter 'import';
  2         4  
  2         67  
6 2     2   1309 use Math::BigInt;
  2         36719  
  2         9  
7              
8             our $VERSION = '0.01';
9             our @EXPORT_OK = qw(to_wei from_wei hex_to_bigint bigint_to_hex);
10              
11             my %UNITS = (
12             wei => 0,
13             kwei => 3,
14             mwei => 6,
15             gwei => 9,
16             szabo => 12,
17             finney => 15,
18             ether => 18,
19             );
20              
21             sub _unit_exp {
22 7     7   18 my ($unit) = @_;
23 7   100     33 $unit = lc($unit // 'ether');
24 7 50       24 die "Web3::Tiny::Util: unknown unit '$unit'\n" unless exists $UNITS{$unit};
25 7         21 return $UNITS{$unit};
26             }
27              
28             # to_wei($amount, $unit = 'ether') -> decimal string (wei)
29             sub to_wei {
30 4     4 0 156206 my ($amount, $unit) = @_;
31 4         17 my $exp = _unit_exp($unit);
32              
33             # split on a decimal point so fractional ether amounts (e.g. "1.5")
34             # convert exactly, without floating-point error
35 4 50       48 my ($sign, $int_part, $frac_part) = ($amount =~ /^(-?)(\d*)(?:\.(\d*))?$/)
36             or die "Web3::Tiny::Util: bad amount '$amount'\n";
37 4   100     22 $int_part ||= '0';
38 4   100     21 $frac_part ||= '';
39 4 50       14 die "Web3::Tiny::Util: '$amount' has more precision than 1 wei\n" if length($frac_part) > $exp;
40 4         12 $frac_part .= '0' x ($exp - length($frac_part));
41              
42 4         28 my $wei = Math::BigInt->new($int_part . $frac_part);
43 4 50       544 $wei = $wei->bneg if $sign eq '-';
44 4         16 return $wei->bstr;
45             }
46              
47             # from_wei($wei, $unit = 'ether') -> decimal string, e.g. "1.5"
48             sub from_wei {
49 3     3 0 859 my ($wei, $unit) = @_;
50 3         11 my $exp = _unit_exp($unit);
51 3 50       9 return "$wei" if $exp == 0;
52              
53 3 50 33     23 my $bi = ref($wei) && $wei->isa('Math::BigInt') ? $wei->copy : Math::BigInt->new("$wei");
54 3         419 my $neg = $bi->is_neg;
55 3         34 $bi->babs;
56              
57 3         320 my $str = $bi->bstr;
58 3 50       217 $str = ('0' x ($exp + 1 - length($str))) . $str if length($str) < $exp + 1;
59              
60 3         9 my $int_part = substr($str, 0, length($str) - $exp);
61 3         6 my $frac_part = substr($str, length($str) - $exp);
62 3         23 $frac_part =~ s/0+$//;
63              
64 3 100       9 my $out = length($frac_part) ? "$int_part.$frac_part" : $int_part;
65 3 50       27 return $neg ? "-$out" : $out;
66             }
67              
68             # hex_to_bigint("0x1a") -> Math::BigInt(26)
69             sub hex_to_bigint {
70 1     1 0 3 my ($hex) = @_;
71 1 50 33     10 $hex = '0x0' unless defined $hex && length($hex);
72 1         7 return Math::BigInt->from_hex($hex);
73             }
74              
75             # bigint_to_hex(26) -> "0x1a"
76             sub bigint_to_hex {
77 1     1 0 1182 my ($n) = @_;
78 1 50 33     12 my $bi = ref($n) && $n->isa('Math::BigInt') ? $n : Math::BigInt->new("$n");
79 1         133 my $hex = lc $bi->as_hex;
80 1         106 return $hex;
81             }
82              
83             1;
84              
85             __END__