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 5 7 71.4
total 83 89 93.2


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