File Coverage

blib/lib/REFECO/Blockchain/Contract/Solidity/ABI/Encoder.pm
Criterion Covered Total %
statement 53 53 100.0
branch 2 4 50.0
condition 3 5 60.0
subroutine 16 16 100.0
pod 7 9 77.7
total 81 87 93.1


line stmt bran cond sub pod time code
1              
2             use strict;
3 4     4   264742 use warnings;
  4         36  
  4         105  
4 4     4   17 no indirect;
  4         8  
  4         93  
5 4     4   1688  
  4         5466  
  4         17  
6             =head1 NAME
7              
8             REFECO::Blockchain::Contract::Solidity::ABI::Encoder - Contract Application Binary Interface argument encoder
9              
10             =head1 VERSION
11              
12             Version 0.001
13              
14             =cut
15              
16             our $VERSION = '0.001';
17              
18             =head1 SYNOPSIS
19              
20             The Contract Application Binary Interface (ABI) is the standard way to interact
21             with contracts (Ethereum), this module aims to be an utility to encode the given
22             data according ABI type specification.
23              
24             my $encoder = REFECO::Blockchain::Contract::Solidity::ABI::Encoder->new();
25             $encoder->function('test')
26             # string
27             ->append(string => 'Hello, World!')
28             # bytes
29             ->append(bytes => unpack("H*", 'Hello, World!'))
30             # tuple
31             ->append('(uint256,address)' => [75000000000000, '0x0000000000000000000000000000000000000000'])
32             # arrays
33             ->append('bool[]', [1, 0, 1, 0])
34             # multidimensional arrays
35             ->append('uint256[][][2]', [[[1]], [[2]]])
36             # tuples arrays and tuples inside tuples
37             ->append('((int256)[2])' => [[[1], [2]]])->encode();
38             ...
39              
40             =head1 AUTHOR
41              
42             Reginaldo Costa, C<< <refeco at cpan.org> >>
43              
44             =head1 BUGS
45              
46             Please report any bugs or feature requests to C<bug-refeco-blockchain-smartcontracts-solidity-abi-encoder at rt.cpan.org>, or through
47             the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=REFECO-Blockchain-Contract-Solidity-ABI-Encoder>. I will be notified, and then you'll
48             automatically be notified of progress on your bug as I make changes.
49              
50             =head1 SUPPORT
51              
52             You can find documentation for this module with the perldoc command.
53              
54             perldoc REFECO::Blockchain::Contract::Solidity::ABI::Encoder
55              
56              
57             You can also look for information at:
58              
59             =over 4
60              
61             =item * RT: CPAN's request tracker (report bugs here)
62              
63             L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=REFECO-Blockchain-Contract-Solidity-ABI-Encoder>
64              
65             =item * CPAN Ratings
66              
67             L<https://cpanratings.perl.org/d/REFECO-Blockchain-Contract-Solidity-ABI-Encoder>
68              
69             =item * Search CPAN
70              
71             L<https://metacpan.org/release/REFECO-Blockchain-Contract-Solidity-ABI-Encoder>
72              
73             =back
74              
75              
76             =head1 ACKNOWLEDGEMENTS
77              
78              
79             =head1 LICENSE AND COPYRIGHT
80              
81             This software is Copyright (c) 2022 by Reginaldo Costa.
82              
83             This is free software, licensed under:
84              
85             The Artistic License 2.0 (GPL Compatible)
86              
87             =cut
88              
89             use Carp;
90 4     4   280 use Digest::Keccak qw(keccak_256_hex);
  4         9  
  4         251  
91 4     4   1751 use REFECO::Blockchain::Contract::Solidity::ABI::Type;
  4         5115  
  4         233  
92 4     4   1757 use REFECO::Blockchain::Contract::Solidity::ABI::Type::Tuple;
  4         13  
  4         208  
93 4     4   1855  
  4         11  
  4         2503  
94             my ($class, %params) = @_;
95              
96 4     4 0 1253 my $self = {};
97             bless $self, $class;
98 4         11 return $self;
99 4         10 }
100 4         12  
101             my $self = shift;
102             return $self->{instances} //= [];
103             }
104 50     50 0 81  
105 50   100     231 my $self = shift;
106             return $self->{function_name};
107             }
108              
109 24     24 1 37 =head2 append
110 24         74  
111             Appends type signature and the respective values to the encoder
112              
113             =over 4
114              
115             =item * C<%param> key is the respective type signature followed by the value e.g. uint256 => 10
116              
117             =back
118              
119             return same L<REFECO::Blockchain::Contract::Solidity::ABI::Encoder> instance
120              
121             =cut
122              
123             my ($self, %param) = @_;
124              
125             for my $type_signature (keys %param) {
126             push(
127             $self->instances->@*,
128 28     28 1 4826 REFECO::Blockchain::Contract::Solidity::ABI::Type::new_type(
129             signature => $type_signature,
130 28         71 data => $param{$type_signature}));
131             }
132              
133             return $self;
134             }
135 28         78  
136             =head2 function
137              
138 27         141 Appends the function name to the encoder, this is optional for when you want the
139             function signature added to the converted string or only the name converted
140              
141             =over 4
142              
143             =item * C<function_name> solidity function name e.g. for `transfer(address,uint256)` will be `transfer`
144              
145             =back
146              
147             return same L<REFECO::Blockchain::Contract::Solidity::ABI::Encoder> instance
148              
149             =cut
150              
151             my ($self, $function_name) = @_;
152             $self->{function_name} = $function_name;
153             return $self;
154             }
155              
156             =head2 generate_function_signature
157 8     8 1 11991  
158 8         25 Based on the given function name and type signatures create the full function
159 8         46 signature
160              
161             =over 4
162              
163             =back
164              
165             string function signature
166              
167             =cut
168              
169             my $self = shift;
170             croak "Missing function name e.g. ->function('name')" unless $self->function_name;
171             my $signature = $self->function_name . '(';
172             $signature .= sprintf("%s,", $_->signature) for $self->instances->@*;
173             chop $signature;
174             return $signature . ')';
175             }
176 8     8 1 33  
177 8 50       17 =head2 encode_function_signature
178 8         17  
179 8         20 Encode function signature, this function can be called directly but in most of
180 8         21 cases you just want to let the module take care of it for you calling `function`
181 8         107 instead
182              
183             =over 4
184              
185             =item C<signature> function signature, if not give method will try to use the one given by `function`
186              
187             =back
188              
189             encoded function signature string prefixed with 0x
190              
191             =cut
192              
193             my ($self, $signature) = @_;
194             return sprintf("0x%.8s", keccak_256_hex($signature // $self->generate_function_signature));
195             }
196              
197             =head2 encode
198              
199             Encodes all appended type signatures and the function name (if given)
200              
201 8     8 1 18 =over 4
202 8   33     32  
203             =back
204              
205             Encoded string, if function name given will be 0x prefixed
206              
207             =cut
208              
209             my $self = shift;
210              
211             my $tuple = REFECO::Blockchain::Contract::Solidity::ABI::Type::Tuple->new;
212             $tuple->{instances} = $self->instances;
213             my @data = $tuple->encode->@*;
214             unshift @data, $self->encode_function_signature if $self->function_name;
215              
216             return join('', @data);
217             }
218 14     14 1 26  
219             =head2 clean
220 14         55  
221 14         36 Clean all the appended type signatures and the function name
222 14         41  
223 8 50       38 =over 4
224              
225 8         128 =back
226              
227             undef
228              
229             =cut
230              
231             my $self = shift;
232             delete $self->{instances};
233             undef $self->{function_name};
234             }
235              
236             1;
237