/ src / Util / UtilResult.php
UtilResult.php
  1  <?php
  2  
  3  namespace BitcoindRPC\Util;
  4  
  5  use BitcoindRPC\RpcResponse;
  6  
  7  class UtilResult
  8  {
  9      private RpcResponse $response;
 10  
 11      public function __construct(RpcResponse $response)
 12      {
 13          $this->response = $response;
 14      }
 15  
 16      public function isSuccess(): bool
 17      {
 18          return $this->response->isSuccess();
 19      }
 20  
 21      public function getData(): mixed
 22      {
 23          return $this->response->getData();
 24      }
 25  
 26      public function getError(): ?string
 27      {
 28          return $this->response->getError();
 29      }
 30  
 31      public function getStatusCode(): int
 32      {
 33          return $this->response->getStatusCode();
 34      }
 35  
 36      public function toArray(): array
 37      {
 38          return $this->response->toArray();
 39      }
 40  
 41      // Multisig specific methods
 42      public function getMultisigInfo(): ?array
 43      {
 44          $data = $this->getData();
 45          return is_array($data) ? $data : null;
 46      }
 47  
 48      public function getMultisigAddress(): ?string
 49      {
 50          $multisig = $this->getMultisigInfo();
 51          return $multisig['address'] ?? null;
 52      }
 53  
 54      public function getMultisigRedeemScript(): ?string
 55      {
 56          $multisig = $this->getMultisigInfo();
 57          return $multisig['redeemScript'] ?? null;
 58      }
 59  
 60      public function getMultisigDescriptor(): ?string
 61      {
 62          $multisig = $this->getMultisigInfo();
 63          return $multisig['descriptor'] ?? null;
 64      }
 65  
 66      // Address derivation methods
 67      public function getDerivedAddresses(): ?array
 68      {
 69          $data = $this->getData();
 70          return is_array($data) ? $data : null;
 71      }
 72  
 73      public function getDerivedAddressCount(): ?int
 74      {
 75          $addresses = $this->getDerivedAddresses();
 76          return is_array($addresses) ? count($addresses) : null;
 77      }
 78  
 79      // Fee estimation methods
 80      public function getFeeEstimation(): ?array
 81      {
 82          $data = $this->getData();
 83          return is_array($data) ? $data : null;
 84      }
 85  
 86      public function getFeeRate(): ?float
 87      {
 88          $estimation = $this->getFeeEstimation();
 89          return $estimation['feerate'] ?? null;
 90      }
 91  
 92      public function getFeeEstimationBlocks(): ?int
 93      {
 94          $estimation = $this->getFeeEstimation();
 95          return $estimation['blocks'] ?? null;
 96      }
 97  
 98      public function getFeeEstimationErrors(): ?array
 99      {
100          $estimation = $this->getFeeEstimation();
101          return $estimation['errors'] ?? null;
102      }
103  
104      // Descriptor info methods
105      public function getDescriptorInfo(): ?array
106      {
107          $data = $this->getData();
108          return is_array($data) ? $data : null;
109      }
110  
111      public function getDescriptorString(): ?string
112      {
113          $info = $this->getDescriptorInfo();
114          return $info['descriptor'] ?? null;
115      }
116  
117      public function getDescriptorChecksum(): ?string
118      {
119          $info = $this->getDescriptorInfo();
120          return $info['checksum'] ?? null;
121      }
122  
123      public function isDescriptorRange(): ?bool
124      {
125          $info = $this->getDescriptorInfo();
126          return $info['isrange'] ?? null;
127      }
128  
129      public function isDescriptorSolvable(): ?bool
130      {
131          $info = $this->getDescriptorInfo();
132          return $info['issolvable'] ?? null;
133      }
134  
135      public function hasDescriptorPrivateKeys(): ?bool
136      {
137          $info = $this->getDescriptorInfo();
138          return $info['hasprivatekeys'] ?? null;
139      }
140  
141      // Index info methods
142      public function getIndexInfo(): ?array
143      {
144          $data = $this->getData();
145          return is_array($data) ? $data : null;
146      }
147  
148      public function getIndexCount(): ?int
149      {
150          $info = $this->getIndexInfo();
151          return is_array($info) ? count($info) : null;
152      }
153  
154      public function getIndexNames(): ?array
155      {
156          $info = $this->getIndexInfo();
157          return is_array($info) ? array_keys($info) : null;
158      }
159  
160      // Message signing methods
161      public function getSignature(): ?string
162      {
163          $data = $this->getData();
164          return is_string($data) ? $data : null;
165      }
166  
167      public function isSignatureValid(): ?bool
168      {
169          $data = $this->getData();
170          return is_bool($data) ? $data : null;
171      }
172  
173      // Address validation methods
174      public function getAddressInfo(): ?array
175      {
176          $data = $this->getData();
177          return is_array($data) ? $data : null;
178      }
179  
180      public function isAddressValid(): ?bool
181      {
182          $info = $this->getAddressInfo();
183          return $info['isvalid'] ?? null;
184      }
185  
186      public function getValidatedAddress(): ?string
187      {
188          $info = $this->getAddressInfo();
189          return $info['address'] ?? null;
190      }
191  
192      public function getScriptPubKey(): ?string
193      {
194          $info = $this->getAddressInfo();
195          return $info['scriptPubKey'] ?? null;
196      }
197  
198      public function isScript(): ?bool
199      {
200          $info = $this->getAddressInfo();
201          return $info['isscript'] ?? null;
202      }
203  
204      public function isWitness(): ?bool
205      {
206          $info = $this->getAddressInfo();
207          return $info['iswitness'] ?? null;
208      }
209  
210      public function getWitnessVersion(): ?int
211      {
212          $info = $this->getAddressInfo();
213          return $info['witness_version'] ?? null;
214      }
215  
216      public function getWitnessProgram(): ?string
217      {
218          $info = $this->getAddressInfo();
219          return $info['witness_program'] ?? null;
220      }
221  
222      // Utility methods
223      public function getUtilSummary(): array
224      {
225          $summary = [
226              'success' => $this->isSuccess(),
227              'error' => $this->getError(),
228              'status_code' => $this->getStatusCode(),
229              'type' => 'unknown'
230          ];
231  
232          if ($this->isSuccess()) {
233              $data = $this->getData();
234              
235              if (is_array($data)) {
236                  // Multisig response
237                  if (isset($data['address']) && isset($data['redeemScript'])) {
238                      $summary['type'] = 'multisig';
239                      $summary['address'] = $data['address'];
240                      $summary['redeem_script'] = $data['redeemScript'];
241                      $summary['descriptor'] = $data['descriptor'] ?? null;
242                  }
243                  // Fee estimation response
244                  elseif (isset($data['feerate'])) {
245                      $summary['type'] = 'fee_estimation';
246                      $summary['feerate'] = $data['feerate'];
247                      $summary['blocks'] = $data['blocks'] ?? null;
248                      $summary['errors'] = $data['errors'] ?? [];
249                  }
250                  // Descriptor info response
251                  elseif (isset($data['descriptor'])) {
252                      $summary['type'] = 'descriptor_info';
253                      $summary['descriptor'] = $data['descriptor'];
254                      $summary['checksum'] = $data['checksum'] ?? null;
255                      $summary['is_range'] = $data['isrange'] ?? false;
256                      $summary['is_solvable'] = $data['issolvable'] ?? false;
257                      $summary['has_private_keys'] = $data['hasprivatekeys'] ?? false;
258                  }
259                  // Index info response
260                  elseif (is_array($data) && !empty($data) && is_array(reset($data))) {
261                      $summary['type'] = 'index_info';
262                      $summary['index_count'] = count($data);
263                      $summary['index_names'] = array_keys($data);
264                  }
265                  // Address validation response
266                  elseif (isset($data['isvalid'])) {
267                      $summary['type'] = 'address_validation';
268                      $summary['is_valid'] = $data['isvalid'];
269                      $summary['address'] = $data['address'] ?? null;
270                      $summary['is_script'] = $data['isscript'] ?? false;
271                      $summary['is_witness'] = $data['iswitness'] ?? false;
272                  }
273                  // Derived addresses response
274                  elseif (is_array($data) && !empty($data) && is_string(reset($data))) {
275                      $summary['type'] = 'derived_addresses';
276                      $summary['address_count'] = count($data);
277                      $summary['addresses'] = $data;
278                  }
279              } elseif (is_string($data)) {
280                  // Message signature response
281                  $summary['type'] = 'signature';
282                  $summary['signature'] = $data;
283              } elseif (is_bool($data)) {
284                  // Message verification response
285                  $summary['type'] = 'verification';
286                  $summary['verified'] = $data;
287              }
288          }
289  
290          return $summary;
291      }
292  
293      public function getAddressDetails(): ?array
294      {
295          $info = $this->getAddressInfo();
296          if (!$info) {
297              return null;
298          }
299  
300          return [
301              'valid' => $info['isvalid'] ?? false,
302              'address' => $info['address'] ?? null,
303              'script_pub_key' => $info['scriptPubKey'] ?? null,
304              'is_script' => $info['isscript'] ?? false,
305              'is_witness' => $info['iswitness'] ?? false,
306              'witness_version' => $info['witness_version'] ?? null,
307              'witness_program' => $info['witness_program'] ?? null,
308              'pubkey' => $info['pubkey'] ?? null,
309              'is_compressed' => $info['iscompressed'] ?? null
310          ];
311      }
312  
313      public function getFeeEstimationDetails(): ?array
314      {
315          $estimation = $this->getFeeEstimation();
316  
317          if (!$estimation) {
318              return null;
319          }
320  
321          return [
322              'feerate_btc_kb' => $estimation['feerate'] ?? null,
323              'feerate_sat_vbyte' => $estimation['feerate'] ? $estimation['feerate'] * 100000 : null,
324              'blocks' => $estimation['blocks'] ?? null,
325              'errors' => $estimation['errors'] ?? [],
326              'estimation_quality' => empty($estimation['errors']) ? 'high' : 'low'
327          ];
328      }
329  
330      public function getMultisigDetails(): ?array
331      {
332          $multisig = $this->getMultisigInfo();
333  
334          if (!$multisig) {
335              return null;
336          }
337  
338          return [
339              'address' => $multisig['address'] ?? null,
340              'redeem_script' => $multisig['redeemScript'] ?? null,
341              'descriptor' => $multisig['descriptor'] ?? null,
342              'address_type' => $this->inferAddressType($multisig['address'] ?? '')
343          ];
344      }
345  
346      private function inferAddressType(string $address): string
347      {
348          if (str_starts_with($address, '1')) {
349              return 'legacy';
350          } elseif (str_starts_with($address, '3')) {
351              return 'p2sh';
352          } elseif (str_starts_with($address, 'bc1')) {
353              return 'bech32';
354          } else {
355              return 'unknown';
356          }
357      }
358  }