Wallet.php
1 <?php 2 3 namespace BitcoindRPC\Wallet; 4 5 use BitcoindRPC\RpcClient; 6 use BitcoindRPC\RpcResponse; 7 8 class Wallet 9 { 10 private RpcClient $client; 11 12 public function __construct(RpcClient $client) 13 { 14 $this->client = $client; 15 } 16 17 public function abandonTransaction(string $txid): WalletResult 18 { 19 $response = $this->client->call('abandontransaction', [$txid]); 20 21 return new WalletResult($response); 22 } 23 24 public function abortRescan(): WalletResult 25 { 26 $response = $this->client->call('abortrescan'); 27 28 return new WalletResult($response); 29 } 30 31 public function addMultisigAddress( 32 int $nrequired, 33 array $keys, 34 string $label = "", 35 string $addressType = "" 36 ): WalletResult { 37 $params = [$nrequired, $keys]; 38 if ($label !== "") $params[] = $label; 39 if ($addressType !== "") $params[] = $addressType; 40 41 $response = $this->client->call('addmultisigaddress', $params); 42 return new WalletResult($response); 43 } 44 45 public function backupWallet(string $destination): WalletResult 46 { 47 $response = $this->client->call('backupwallet', [$destination]); 48 return new WalletResult($response); 49 } 50 51 public function bumpFee(string $txid, array $options = []): WalletResult 52 { 53 $params = [$txid]; 54 if (!empty($options)) $params[] = $options; 55 56 $response = $this->client->call('bumpfee', $params); 57 return new WalletResult($response); 58 } 59 60 public function createWallet( 61 string $walletName, 62 bool $disablePrivateKeys = false, 63 bool $blank = false, 64 string $passphrase = "", 65 bool $avoidReuse = false, 66 bool $descriptors = false, 67 bool $loadOnStartup = true 68 ): WalletResult { 69 $params = [$walletName, $disablePrivateKeys, $blank, $passphrase, $avoidReuse]; 70 if ($descriptors) $params[] = $descriptors; 71 $params[] = $loadOnStartup; 72 73 $response = $this->client->call('createwallet', $params); 74 return new WalletResult($response); 75 } 76 77 public function dumpPrivKey(string $address): WalletResult 78 { 79 $response = $this->client->call('dumpprivkey', [$address]); 80 return new WalletResult($response); 81 } 82 83 public function dumpWallet(string $filename): WalletResult 84 { 85 $response = $this->client->call('dumpwallet', [$filename]); 86 return new WalletResult($response); 87 } 88 89 public function encryptWallet(string $passphrase): WalletResult 90 { 91 $response = $this->client->call('encryptwallet', [$passphrase]); 92 return new WalletResult($response); 93 } 94 95 public function getAddressesByLabel(string $label): WalletResult 96 { 97 $response = $this->client->call('getaddressesbylabel', [$label]); 98 return new WalletResult($response); 99 } 100 101 public function getAddressInfo(string $address): WalletResult 102 { 103 $response = $this->client->call('getaddressinfo', [$address]); 104 return new WalletResult($response); 105 } 106 107 public function getBalance( 108 string $dummy = "*", 109 int $minconf = 0, 110 bool $includeWatchonly = false, 111 bool $avoidReuse = true 112 ): WalletResult { 113 $response = $this->client->call('getbalance', [$dummy, $minconf, $includeWatchonly, $avoidReuse]); 114 return new WalletResult($response); 115 } 116 117 public function getBalances(): WalletResult 118 { 119 $response = $this->client->call('getbalances'); 120 return new WalletResult($response); 121 } 122 123 public function getNewAddress(string $label = "", string $addressType = ""): WalletResult 124 { 125 $params = []; 126 if ($label !== "") $params[] = $label; 127 if ($addressType !== "") $params[] = $addressType; 128 129 $response = $this->client->call('getnewaddress', $params); 130 return new WalletResult($response); 131 } 132 133 public function getRawChangeAddress(string $addressType = ""): WalletResult 134 { 135 $params = []; 136 if ($addressType !== "") $params[] = $addressType; 137 138 $response = $this->client->call('getrawchangeaddress', $params); 139 return new WalletResult($response); 140 } 141 142 public function getReceivedByAddress(string $address, int $minconf = 1): WalletResult 143 { 144 $response = $this->client->call('getreceivedbyaddress', [$address, $minconf]); 145 return new WalletResult($response); 146 } 147 148 public function getReceivedByLabel(string $label, int $minconf = 1): WalletResult 149 { 150 $response = $this->client->call('getreceivedbylabel', [$label, $minconf]); 151 return new WalletResult($response); 152 } 153 154 public function getTransaction( 155 string $txid, 156 bool $includeWatchonly = false, 157 bool $verbose = true 158 ): WalletResult { 159 $response = $this->client->call('gettransaction', [$txid, $includeWatchonly, $verbose]); 160 return new WalletResult($response); 161 } 162 163 public function getUnconfirmedBalance(): WalletResult 164 { 165 $response = $this->client->call('getunconfirmedbalance'); 166 return new WalletResult($response); 167 } 168 169 public function getWalletInfo(): WalletResult 170 { 171 $response = $this->client->call('getwalletinfo'); 172 return new WalletResult($response); 173 } 174 175 public function importAddress( 176 string $address, 177 string $label = "", 178 bool $rescan = true, 179 bool $p2sh = false 180 ): WalletResult { 181 $params = [$address, $label, $rescan]; 182 if ($p2sh) $params[] = $p2sh; 183 184 $response = $this->client->call('importaddress', $params); 185 return new WalletResult($response); 186 } 187 188 public function importDescriptors(array $requests): WalletResult 189 { 190 $response = $this->client->call('importdescriptors', [$requests]); 191 return new WalletResult($response); 192 } 193 194 public function importMulti(array $requests, array $options = []): WalletResult 195 { 196 $params = [$requests]; 197 if (!empty($options)) $params[] = $options; 198 199 $response = $this->client->call('importmulti', $params); 200 return new WalletResult($response); 201 } 202 203 public function importPrivKey(string $privkey, string $label = "", bool $rescan = true): WalletResult 204 { 205 $response = $this->client->call('importprivkey', [$privkey, $label, $rescan]); 206 return new WalletResult($response); 207 } 208 209 public function importPrunedFunds(string $rawtransaction, string $txoutproof): WalletResult 210 { 211 $response = $this->client->call('importprunedfunds', [$rawtransaction, $txoutproof]); 212 return new WalletResult($response); 213 } 214 215 public function importPubkey(string $pubkey, string $label = "", bool $rescan = true): WalletResult 216 { 217 $response = $this->client->call('importpubkey', [$pubkey, $label, $rescan]); 218 return new WalletResult($response); 219 } 220 221 public function importWallet(string $filename): WalletResult 222 { 223 $response = $this->client->call('importwallet', [$filename]); 224 return new WalletResult($response); 225 } 226 227 public function keyPoolRefill(int $newsize = 100): WalletResult 228 { 229 $response = $this->client->call('keypoolrefill', [$newsize]); 230 return new WalletResult($response); 231 } 232 233 public function listAddressGroupings(): WalletResult 234 { 235 $response = $this->client->call('listaddressgroupings'); 236 return new WalletResult($response); 237 } 238 239 public function listLabels(string $purpose = ""): WalletResult 240 { 241 $params = []; 242 if ($purpose !== "") $params[] = $purpose; 243 244 $response = $this->client->call('listlabels', $params); 245 return new WalletResult($response); 246 } 247 248 public function listLockUnspent(): WalletResult 249 { 250 $response = $this->client->call('listlockunspent'); 251 return new WalletResult($response); 252 } 253 254 public function listReceivedByAddress( 255 int $minconf = 1, 256 bool $includeEmpty = false, 257 bool $includeWatchonly = false, 258 string $addressFilter = "" 259 ): WalletResult { 260 $params = [$minconf, $includeEmpty, $includeWatchonly]; 261 if ($addressFilter !== "") $params[] = $addressFilter; 262 263 $response = $this->client->call('listreceivedbyaddress', $params); 264 return new WalletResult($response); 265 } 266 267 public function listReceivedByLabel( 268 int $minconf = 1, 269 bool $includeEmpty = false, 270 bool $includeWatchonly = false 271 ): WalletResult { 272 $response = $this->client->call('listreceivedbylabel', [$minconf, $includeEmpty, $includeWatchonly]); 273 return new WalletResult($response); 274 } 275 276 public function listSinceBlock( 277 string $blockhash = "", 278 int $targetConfirmations = 1, 279 bool $includeWatchonly = false, 280 bool $includeRemoved = false 281 ): WalletResult { 282 $response = $this->client->call('listsinceblock', [ 283 $blockhash, $targetConfirmations, $includeWatchonly, $includeRemoved 284 ]); 285 return new WalletResult($response); 286 } 287 288 public function listTransactions( 289 string $label = "*", 290 int $count = 10, 291 int $skip = 0, 292 bool $includeWatchonly = false 293 ): WalletResult { 294 $response = $this->client->call('listtransactions', [$label, $count, $skip, $includeWatchonly]); 295 return new WalletResult($response); 296 } 297 298 public function listUnspent( 299 int $minconf = 1, 300 int $maxconf = 9999999, 301 array $addresses = [], 302 bool $includeUnsafe = true, 303 array $queryOptions = [] 304 ): WalletResult { 305 $params = [$minconf, $maxconf]; 306 if (!empty($addresses)) $params[] = $addresses; 307 $params[] = $includeUnsafe; 308 if (!empty($queryOptions)) $params[] = $queryOptions; 309 310 $response = $this->client->call('listunspent', $params); 311 return new WalletResult($response); 312 } 313 314 public function listWalletDir(): WalletResult 315 { 316 $response = $this->client->call('listwalletdir'); 317 return new WalletResult($response); 318 } 319 320 public function listWallets(): WalletResult 321 { 322 $response = $this->client->call('listwallets'); 323 return new WalletResult($response); 324 } 325 326 public function loadWallet(string $filename): WalletResult 327 { 328 $response = $this->client->call('loadwallet', [$filename]); 329 return new WalletResult($response); 330 } 331 332 public function lockUnspent(bool $unlock, array $transactions = []): WalletResult 333 { 334 $params = [$unlock]; 335 if (!empty($transactions)) $params[] = $transactions; 336 337 $response = $this->client->call('lockunspent', $params); 338 return new WalletResult($response); 339 } 340 341 public function psbtBumpFee(string $txid, array $options = []): WalletResult 342 { 343 $params = [$txid]; 344 if (!empty($options)) $params[] = $options; 345 346 $response = $this->client->call('psbtbumpfee', $params); 347 return new WalletResult($response); 348 } 349 350 public function removePrunedFunds(string $txid): WalletResult 351 { 352 $response = $this->client->call('removeprunedfunds', [$txid]); 353 return new WalletResult($response); 354 } 355 356 public function rescanBlockchain(int $startHeight = 0, ?int $stopHeight = null): WalletResult 357 { 358 $params = [$startHeight]; 359 if ($stopHeight !== null) $params[] = $stopHeight; 360 361 $response = $this->client->call('rescanblockchain', $params); 362 return new WalletResult($response); 363 } 364 365 public function send(array $outputs, int $confTarget = 6, string $estimateMode = "UNSET", ?float $feeRate = null): WalletResult 366 { 367 $params = [$outputs, $confTarget, $estimateMode]; 368 if ($feeRate !== null) $params[] = $feeRate; 369 370 $response = $this->client->call('send', $params); 371 return new WalletResult($response); 372 } 373 374 public function sendMany( 375 array $outputs, 376 int $minconf = 1, 377 string $comment = "", 378 array $subtractFeeFrom = [], 379 bool $replaceable = false, 380 int $confTarget = 6, 381 string $estimateMode = "UNSET", 382 ?float $feeRate = null 383 ): WalletResult { 384 $params = [$outputs, $minconf, $comment]; 385 if (!empty($subtractFeeFrom)) $params[] = $subtractFeeFrom; 386 $params[] = $replaceable; 387 $params[] = $confTarget; 388 $params[] = $estimateMode; 389 if ($feeRate !== null) $params[] = $feeRate; 390 391 $response = $this->client->call('sendmany', $params); 392 return new WalletResult($response); 393 } 394 395 public function sendToAddress( 396 string $address, 397 float $amount, 398 string $comment = "", 399 string $commentTo = "", 400 bool $subtractFeeFromAmount = false, 401 bool $replaceable = false, 402 int $confTarget = 6, 403 string $estimateMode = "UNSET", 404 ?float $feeRate = null 405 ): WalletResult { 406 $params = [ 407 $address, $amount, $comment, $commentTo, 408 $subtractFeeFromAmount, $replaceable, $confTarget, $estimateMode 409 ]; 410 if ($feeRate !== null) $params[] = $feeRate; 411 412 $response = $this->client->call('sendtoaddress', $params); 413 return new WalletResult($response); 414 } 415 416 public function setHdSeed(bool $newkeypool = true, string $seed = ""): WalletResult 417 { 418 $params = [$newkeypool]; 419 if ($seed !== "") $params[] = $seed; 420 421 $response = $this->client->call('sethdseed', $params); 422 return new WalletResult($response); 423 } 424 425 public function setLabel(string $address, string $label): WalletResult 426 { 427 $response = $this->client->call('setlabel', [$address, $label]); 428 return new WalletResult($response); 429 } 430 431 public function setTxFee(float $amount): WalletResult 432 { 433 $response = $this->client->call('settxfee', [$amount]); 434 return new WalletResult($response); 435 } 436 437 public function setWalletFlag(string $flag, bool $value): WalletResult 438 { 439 $response = $this->client->call('setwalletflag', [$flag, $value]); 440 return new WalletResult($response); 441 } 442 443 public function signMessage(string $address, string $message): WalletResult 444 { 445 $response = $this->client->call('signmessage', [$address, $message]); 446 return new WalletResult($response); 447 } 448 449 public function signRawTransactionWithWallet( 450 string $hexstring, 451 array $prevtxs = [], 452 string $sighashtype = "ALL" 453 ): WalletResult { 454 $params = [$hexstring]; 455 if (!empty($prevtxs)) $params[] = $prevtxs; 456 $params[] = $sighashtype; 457 458 $response = $this->client->call('signrawtransactionwithwallet', $params); 459 return new WalletResult($response); 460 } 461 462 public function unloadWallet(string $walletName = "", ?bool $loadOnStartup = null): WalletResult 463 { 464 $params = []; 465 if ($walletName !== "") $params[] = $walletName; 466 if ($loadOnStartup !== null) $params[] = $loadOnStartup; 467 468 $response = $this->client->call('unloadwallet', $params); 469 return new WalletResult($response); 470 } 471 472 public function upgradeWallet(?int $version = null): WalletResult 473 { 474 $params = []; 475 if ($version !== null) $params[] = $version; 476 477 $response = $this->client->call('upgradewallet', $params); 478 return new WalletResult($response); 479 } 480 481 public function walletCreateFundedPsbt( 482 array $inputs, 483 array $outputs, 484 int $locktime = 0, 485 array $options = [], 486 bool $bip32derivs = false 487 ): WalletResult { 488 $params = [$inputs, $outputs, $locktime]; 489 if (!empty($options)) $params[] = $options; 490 $params[] = $bip32derivs; 491 492 $response = $this->client->call('walletcreatefundedpsbt', $params); 493 return new WalletResult($response); 494 } 495 496 public function walletLock(): WalletResult 497 { 498 $response = $this->client->call('walletlock'); 499 return new WalletResult($response); 500 } 501 502 public function walletPassphrase(string $passphrase, int $timeout): WalletResult 503 { 504 $response = $this->client->call('walletpassphrase', [$passphrase, $timeout]); 505 return new WalletResult($response); 506 } 507 508 public function walletPassphraseChange(string $oldpassphrase, string $newpassphrase): WalletResult 509 { 510 $response = $this->client->call('walletpassphrasechange', [$oldpassphrase, $newpassphrase]); 511 return new WalletResult($response); 512 } 513 514 public function walletProcessPsbt( 515 string $psbt, 516 bool $sign = true, 517 string $sighashtype = "ALL", 518 bool $bip32derivs = false 519 ): WalletResult { 520 $response = $this->client->call('walletprocesspsbt', [$psbt, $sign, $sighashtype, $bip32derivs]); 521 return new WalletResult($response); 522 } 523 524 // Utility methods 525 public function getDetailedBalance(): array 526 { 527 $result = $this->getBalances(); 528 if (!$result->isSuccess()) { 529 return []; 530 } 531 532 $data = $result->getData(); 533 $mine = $data['mine'] ?? []; 534 $watchonly = $data['watchonly'] ?? []; 535 536 return [ 537 'total' => ($mine['trusted'] ?? 0) + ($mine['untrusted_pending'] ?? 0) + ($mine['immature'] ?? 0), 538 'confirmed' => $mine['trusted'] ?? 0, 539 'unconfirmed' => $mine['untrusted_pending'] ?? 0, 540 'immature' => $mine['immature'] ?? 0, 541 'watchonly' => ($watchonly['trusted'] ?? 0) + ($watchonly['untrusted_pending'] ?? 0) + ($watchonly['immature'] ?? 0), 542 ]; 543 } 544 545 public function createReceivingAddress(string $label = "", string $addressType = "bech32"): ?string 546 { 547 $result = $this->getNewAddress($label, $addressType); 548 return $result->isSuccess() ? $result->getData() : null; 549 } 550 551 public function sendPayment( 552 string $toAddress, 553 float $amount, 554 string $description = "", 555 bool $subtractFee = false 556 ): ?string { 557 $result = $this->sendToAddress( 558 address: $toAddress, 559 amount: $amount, 560 comment: $description, 561 subtractFeeFromAmount: $subtractFee 562 ); 563 return $result->isSuccess() ? $result->getData() : null; 564 } 565 }