File Coverage

blib/lib/Blockchain/Ethereum/ABI/Encoder.pm
Criterion Covered Total %
statement 51 51 100.0
branch 2 4 50.0
condition 3 5 60.0
subroutine 16 16 100.0
pod 5 7 71.4
total 77 83 92.7


line stmt bran cond sub pod time code
1             package Blockchain::Ethereum::ABI::Encoder;
2              
3 4     4   281397 use v5.26;
  4         57  
4 4     4   34 use strict;
  4         19  
  4         92  
5 4     4   36 use warnings;
  4         8  
  4         118  
6              
7 4     4   21 use Carp;
  4         8  
  4         302  
8 4     4   1947 use Digest::Keccak qw(keccak_256_hex);
  4         5964  
  4         333  
9              
10 4     4   1805 use Blockchain::Ethereum::ABI::Type;
  4         13  
  4         126  
11 4     4   1719 use Blockchain::Ethereum::ABI::Type::Tuple;
  4         13  
  4         2078  
12              
13             sub new {
14 4     4 0 1445 return bless {}, shift;
15             }
16              
17             sub _instances {
18 50     50   87 my $self = shift;
19 50   100     316 return $self->{instances} //= [];
20             }
21              
22             sub function_name {
23 24     24 0 40 my $self = shift;
24 24         89 return $self->{function_name};
25             }
26              
27             sub append {
28 28     28 1 6203 my ($self, %param) = @_;
29              
30 28         101 state $type = Blockchain::Ethereum::ABI::Type->new;
31              
32 28         102 for my $type_signature (keys %param) {
33             push(
34             $self->_instances->@*,
35             $type->new_type(
36             signature => $type_signature,
37 28         90 data => $param{$type_signature}));
38             }
39              
40 27         151 return $self;
41             }
42              
43             sub function {
44 8     8 1 16703 my ($self, $function_name) = @_;
45 8         27 $self->{function_name} = $function_name;
46 8         52 return $self;
47             }
48              
49             sub generate_function_signature {
50 8     8 1 16 my $self = shift;
51 8 50       43 croak "Missing function name e.g. ->function('name')" unless $self->function_name;
52 8         44 my $signature = $self->function_name . '(';
53 8         47 $signature .= sprintf("%s,", $_->_signature) for $self->_instances->@*;
54 8         31 chop $signature;
55 8         118 return $signature . ')';
56             }
57              
58             sub encode_function_signature {
59 8     8 1 22 my ($self, $signature) = @_;
60 8   33     40 return sprintf("0x%.8s", keccak_256_hex($signature // $self->generate_function_signature));
61             }
62              
63             sub encode {
64 14     14 1 29 my $self = shift;
65              
66 14         58 my $tuple = Blockchain::Ethereum::ABI::Type::Tuple->new;
67 14         45 $tuple->{instances} = $self->_instances;
68 14         43 my @data = $tuple->encode->@*;
69 8 50       34 unshift @data, $self->encode_function_signature if $self->function_name;
70              
71 8         32 $self->_clean;
72              
73 8         248 return join('', @data);
74             }
75              
76             sub _clean {
77 15     15   5406 my $self = shift;
78 15         48 delete $self->{instances};
79 15         36 undef $self->{function_name};
80             }
81              
82             =pod
83              
84             =encoding UTF-8
85              
86             =head1 NAME
87              
88             Blockchain::Ethereum::ABI::Encoder - Contract ABI argument encoder
89              
90             =head1 SYNOPSIS
91              
92             Allows you to encode contract ABI arguments
93              
94             my $encoder = Blockchain::Ethereum::ABI::Encoder->new();
95             $encoder->function('test')
96             # string
97             ->append(string => 'Hello, World!')
98             # bytes
99             ->append(bytes => unpack("H*", 'Hello, World!'))
100             # tuple
101             ->append('(uint256,address)' => [75000000000000, '0x0000000000000000000000000000000000000000'])
102             # arrays
103             ->append('bool[]', [1, 0, 1, 0])
104             # multidimensional arrays
105             ->append('uint256[][][2]', [[[1]], [[2]]])
106             # tuples arrays and tuples inside tuples
107             ->append('((int256)[2])' => [[[1], [2]]])->encode();
108             ...
109              
110             =head1 METHODS
111              
112             =head2 append
113              
114             Appends type signature and the respective values to the encoder.
115              
116             Usage:
117              
118             append(signature => value) -> L
119              
120             =over 4
121              
122             =item * C<%param> key is the respective type signature followed by the value e.g. uint256 => 10
123              
124             =back
125              
126             Returns C<$self>
127              
128             =head2 function
129              
130             Appends the function name to the encoder, this is optional for when you want the
131             function signature added to the encoded string or only the function name encoded.
132              
133             Usage:
134              
135             function(string) -> L
136              
137             =over 4
138              
139             =item * C<$function_name> solidity function name e.g. for `transfer(address,uint256)` will be `transfer`
140              
141             =back
142              
143             Returns C<$self>
144              
145             =head2 generate_function_signature
146              
147             Based on the given function name and type signatures create the complete function
148             signature.
149              
150             Usage:
151              
152             generate_function_signature() -> string
153              
154             =over 4
155              
156             =back
157              
158             Returns the function signature string
159              
160             =head2 encode_function_signature
161              
162             Encode function signature keccak_256/sha3
163              
164             Usage:
165              
166             encode_function_signature('transfer(address,uint)') -> encoded string
167              
168             =over 4
169              
170             =item * C<$signature> (Optional) function signature, if not given, will try to use the appended function name
171              
172             =back
173              
174             Returns the encoded string 0x prefixed
175              
176             =head2 encode
177              
178             Encodes appended signatures and the function name (when given)
179              
180             Usage:
181              
182             encode() -> encoded string
183              
184             =over 4
185              
186             =back
187              
188             Returns the encoded string, if function name was given will be 0x prefixed
189              
190             =head1 AUTHOR
191              
192             Reginaldo Costa, C<< >>
193              
194             =head1 BUGS
195              
196             Please report any bugs or feature requests to L
197              
198             =head1 SUPPORT
199              
200             You can find documentation for this module with the perldoc command.
201              
202             perldoc Blockchain::Ethereum::ABI::Encoder
203              
204             =head1 LICENSE AND COPYRIGHT
205              
206             This software is Copyright (c) 2022 by REFECO.
207              
208             This is free software, licensed under:
209              
210             The MIT License
211              
212             =cut
213              
214             1;