File Coverage

blib/lib/REFECO/Blockchain/Contract/Solidity/ABI/Encoder.pm
Criterion Covered Total %
statement 56 56 100.0
branch 2 4 50.0
condition 3 5 60.0
subroutine 17 17 100.0
pod 6 7 85.7
total 84 89 94.3


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