File Coverage

blib/lib/Ethereum/RPC/Contract/ContractTransaction.pm
Criterion Covered Total %
statement 18 45 40.0
branch 0 16 0.0
condition 0 24 0.0
subroutine 6 10 60.0
pod 3 3 100.0
total 27 98 27.5


line stmt bran cond sub pod time code
1             package Ethereum::RPC::Contract::ContractTransaction;
2              
3 4     4   28 use strict;
  4         11  
  4         120  
4 4     4   26 use warnings;
  4         10  
  4         175  
5              
6             our $VERSION = '0.04';
7              
8             =head1 NAME
9              
10             Ethereum::RPC::Contract::ContractTransaction - Centralize contract transactions
11              
12             =cut
13              
14 4     4   22 use Moo;
  4         8  
  4         24  
15 4     4   4050 use Future;
  4         49915  
  4         127  
16              
17 4     4   31 use Ethereum::RPC::Contract::ContractResponse;
  4         11  
  4         90  
18 4     4   1661 use Ethereum::RPC::Contract::Helper::UnitConversion;
  4         14  
  4         2751  
19              
20             has contract_address => (is => 'ro');
21             has rpc_client => (
22             is => 'ro',
23             lazy => 1
24             );
25              
26             sub _build_rpc_client {
27 0     0     return Ethereum::RPC::Client->new;
28             }
29              
30             has data => (
31             is => 'ro',
32             required => 1
33             );
34              
35             has from => (is => 'ro');
36             has gas => (is => 'ro');
37             has gas_price => (is => 'ro');
38             has max_fee_per_gas => (is => 'ro');
39             has max_priority_fee_per_gas => (is => 'ro');
40              
41             =head2 call_transaction
42              
43             Call a public functions and variables from a ethereum contract
44              
45             Return:
46             Ethereum::RPC::Contract::ContractResponse, error message
47              
48             =cut
49              
50             sub call_transaction {
51 0     0 1   my ($self, $block) = @_;
52              
53 0   0       my $res = $self->rpc_client->eth_call([{
54             to => $self->contract_address,
55             data => $self->data,
56             },
57             $block // "latest"
58             ]);
59              
60 0           my $future = Future->new;
61 0 0 0       return $future->done(Ethereum::RPC::Contract::ContractResponse->new({response => $res})) if $res and $res =~ /^0x/;
62 0   0       return $future->fail($res || "Can't call transaction");
63              
64             }
65              
66             =head2 send_transaction
67              
68             Send a transaction to a payable functions from a ethereum contract
69              
70             The parameter GAS is required to send a payable request.
71              
72             Return:
73             Ethereum::RPC::Contract::ContractResponse, error message
74              
75             =cut
76              
77             sub send_transaction {
78 0     0 1   my $self = shift;
79              
80 0           my $future = Future->new;
81              
82 0           my $params = {
83             to => $self->contract_address,
84             from => $self->from,
85             data => $self->data,
86             };
87              
88 0 0         $params->{gas} = Ethereum::RPC::Contract::Helper::UnitConversion::to_wei($self->gas) if $self->gas;
89 0 0         $params->{gasPrice} = $self->gas_price if $self->gas_price;
90 0 0         $params->{maxFeePerGas} = $self->max_fee_per_gas if $self->max_fee_per_gas;
91 0 0         $params->{maxPriorityFeePerGas} = $self->max_priority_fee_per_gas if $self->max_priority_fee_per_gas;
92              
93 0           my $res = $self->rpc_client->eth_sendTransaction([$params]);
94              
95 0 0 0       return $future->done(Ethereum::RPC::Contract::ContractResponse->new({response => $res})) if $res and $res =~ /^0x/;
96 0   0       return $future->fail($res || "Can't send transaction");
97              
98             }
99              
100             =head2 get_contract_address
101              
102             Try to get a contract address based on a transaction hash
103              
104             Parameters:
105             $wait_seconds ( Optional - max time to wait for the contract address response ),
106             $send_response ( Optional - response of the send method, if not informed send a new transaction and then try to get the address ),
107              
108             Return:
109             Ethereum::Contract::ContractResponse
110              
111             =cut
112              
113             sub get_contract_address {
114              
115 0     0 1   my ($self, $wait_seconds, $send_response) = @_;
116              
117 0   0       my $transaction = $send_response // $self->send_transaction();
118 0 0         return $transaction if $transaction->is_failed;
119              
120 0           my $deployed = $self->rpc_client->eth_getTransactionReceipt($transaction->get->response);
121              
122 0   0       while ($wait_seconds and not $deployed and $wait_seconds > 0) {
      0        
123 0           sleep(1);
124 0           $wait_seconds--;
125 0           $deployed = $self->rpc_client->eth_getTransactionReceipt($transaction->get->response);
126             }
127              
128 0           my $future = Future->new;
129 0 0 0       return $future->done(Ethereum::RPC::Contract::ContractResponse->new({response => $deployed->{contractAddress}}))
130             if $deployed and ref($deployed) eq 'HASH';
131              
132 0           return $future->fail("Can't get the contract address for transaction: " . $transaction->get->response);
133              
134             }
135              
136             1;