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   281405 use v5.26;
  4         49  
4 4     4   25 use strict;
  4         10  
  4         104  
5 4     4   23 use warnings;
  4         8  
  4         122  
6 4     4   1863 no indirect;
  4         4602  
  4         21  
7              
8             our $VERSION = '0.003';
9              
10 4     4   305 use Carp;
  4         11  
  4         266  
11 4     4   1742 use Digest::Keccak qw(keccak_256_hex);
  4         5645  
  4         279  
12              
13 4     4   1865 use REFECO::Blockchain::Contract::Solidity::ABI::Type;
  4         13  
  4         216  
14 4     4   1856 use REFECO::Blockchain::Contract::Solidity::ABI::Type::Tuple;
  4         13  
  4         2792  
15              
16             sub new {
17 4     4 0 1637 my ($class, %params) = @_;
18              
19 4         13 my $self = {};
20 4         33 bless $self, $class;
21 4         17 return $self;
22             }
23              
24             sub _instances {
25 50     50   93 my $self = shift;
26 50   100     283 return $self->{instances} //= [];
27             }
28              
29             sub function_name {
30 24     24 1 44 my $self = shift;
31 24         91 return $self->{function_name};
32             }
33              
34             sub append {
35 28     28 1 5734 my ($self, %param) = @_;
36              
37 28         87 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         83 data => $param{$type_signature}));
43             }
44              
45 27         162 return $self;
46             }
47              
48             sub function {
49 8     8 1 16661 my ($self, $function_name) = @_;
50 8         42 $self->{function_name} = $function_name;
51 8         70 return $self;
52             }
53              
54             sub generate_function_signature {
55 8     8 1 21 my $self = shift;
56 8 50       26 croak "Missing function name e.g. ->function('name')" unless $self->function_name;
57 8         23 my $signature = $self->function_name . '(';
58 8         24 $signature .= sprintf("%s,", $_->signature) for $self->_instances->@*;
59 8         24 chop $signature;
60 8         122 return $signature . ')';
61             }
62              
63             sub encode_function_signature {
64 8     8 1 21 my ($self, $signature) = @_;
65 8   33     53 return sprintf("0x%.8s", keccak_256_hex($signature // $self->generate_function_signature));
66             }
67              
68             sub encode {
69 14     14 1 33 my $self = shift;
70              
71 14         58 my $tuple = REFECO::Blockchain::Contract::Solidity::ABI::Type::Tuple->new;
72 14         48 $tuple->{instances} = $self->_instances;
73 14         49 my @data = $tuple->encode->@*;
74 8 50       33 unshift @data, $self->encode_function_signature if $self->function_name;
75              
76 8         35 $self->_clean;
77              
78 8         260 return join('', @data);
79             }
80              
81             sub _clean {
82 15     15   5221 my $self = shift;
83 15         49 delete $self->{instances};
84 15         45 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             append(signature => value) -> L<REFECO::Blockchain::Contract::Solidity::ABI::Encoder>
127              
128             =over 4
129              
130             =item * C<%param> key is the respective type signature followed by the value e.g. uint256 => 10
131              
132             =back
133              
134             Returns C<$self>
135              
136             =head2 function
137              
138             Appends the function name to the encoder, this is optional for when you want the
139             function signature added to the encoded string or only the function name encoded.
140              
141             Usage:
142             function(string) -> L<REFECO::Blockchain::Contract::Solidity::ABI::Encoder>
143              
144             =over 4
145              
146             =item * C<function_name> solidity function name e.g. for `transfer(address,uint256)` will be `transfer`
147              
148             =back
149              
150             Returns C<$self>
151              
152             =head2 generate_function_signature
153              
154             Based on the given function name and type signatures create the complete function
155             signature
156              
157             Usage:
158             generate_function_signature() -> string
159              
160             =over 4
161              
162             =back
163              
164             Returns the function signature string
165              
166             =head2 encode_function_signature
167              
168             Encode function signature keccak_256/sha3
169              
170             Usage:
171             encode_function_signature('transfer(address,uint)') -> encoded string
172              
173             =over 4
174              
175             =item C<signature> function signature, if not given, will try to use the appended function name
176              
177             =back
178              
179             Returns encoded string 0x prefixed
180              
181             =head2 encode
182              
183             Encodes appended signatures and the function name (when given)
184              
185             =over 4
186              
187             =back
188              
189             Returns encoded string, if function name given will be 0x prefixed
190              
191             =head1 AUTHOR
192              
193             Reginaldo Costa, C<< <refeco at cpan.org> >>
194              
195             =head1 BUGS
196              
197             Please report any bugs or feature requests to L<https://github.com/refeco/perl-ABI>
198              
199             =head1 SUPPORT
200              
201             You can find documentation for this module with the perldoc command.
202              
203             perldoc REFECO::Blockchain::Contract::Solidity::ABI::Encoder
204              
205             =head1 LICENSE AND COPYRIGHT
206              
207             This software is Copyright (c) 2022 by Reginaldo Costa.
208              
209             This is free software, licensed under:
210              
211             The Artistic License 2.0 (GPL Compatible)
212              
213             =cut