public function testUnspentOutputFinder() { //some addresses with known unspent outputs, and some without any $addresses = array('2NG3QEhJc1xzN5qxPdNAZfGaTdGAv3ixMbH', '2NA7zpiq5PcYUx6oraEwz8zPzn6HefSvdLA', '2Mu1xrQAEd8LsiRHNvgXDaU8kQU5WKqzCq7', '2N9ijhGSX3kGbe16RMCQ2hviH8RLAVdaqZg'); $blockchainDataService = new BlocktrailBitcoinService("MY_APIKEY", "MY_APISECRET", "BTC", true, 'v1'); $unspenOutputFinder = new UnspentOutputFinder($blockchainDataService); //get unspent outputs for an array of addresses $result = $unspenOutputFinder->getUTXOs($addresses); $this->assertEquals(3, count($result), "expected results for 3 of the 4 given addresses"); $this->assertArrayHasKey('2NG3QEhJc1xzN5qxPdNAZfGaTdGAv3ixMbH', $result); $this->assertArrayHasKey('2NA7zpiq5PcYUx6oraEwz8zPzn6HefSvdLA', $result); $this->assertArrayHasKey('2N9ijhGSX3kGbe16RMCQ2hviH8RLAVdaqZg', $result); $this->assertEquals(2, count($result['2NA7zpiq5PcYUx6oraEwz8zPzn6HefSvdLA']), "expected address to have 2 unspent outputs"); $this->assertArrayHasKey('hash', $result['2NA7zpiq5PcYUx6oraEwz8zPzn6HefSvdLA'][0]); $this->assertArrayHasKey('index', $result['2NA7zpiq5PcYUx6oraEwz8zPzn6HefSvdLA'][0]); $this->assertArrayHasKey('value', $result['2NA7zpiq5PcYUx6oraEwz8zPzn6HefSvdLA'][0]); $this->assertArrayHasKey('script_hex', $result['2NA7zpiq5PcYUx6oraEwz8zPzn6HefSvdLA'][0]); $this->assertEquals(10000000, $result['2NA7zpiq5PcYUx6oraEwz8zPzn6HefSvdLA'][0]['value']); $this->assertEquals(10000000, $result['2NA7zpiq5PcYUx6oraEwz8zPzn6HefSvdLA'][1]['value']); $total = $result['2NG3QEhJc1xzN5qxPdNAZfGaTdGAv3ixMbH'][0]['value'] + $result['2N9ijhGSX3kGbe16RMCQ2hviH8RLAVdaqZg'][0]['value'] + $result['2NA7zpiq5PcYUx6oraEwz8zPzn6HefSvdLA'][0]['value'] + $result['2NA7zpiq5PcYUx6oraEwz8zPzn6HefSvdLA'][1]['value']; $this->assertEquals(40000000, $total); }
/** * discover funds in the wallet * * @param int $increment how many addresses to scan at a time * @return array */ public function discoverWalletFunds($increment = 200) { $totalBalance = 0; $totalUTXOs = 0; $totalAddressesGenerated = 0; $addressUTXOs = array(); //addresses and their utxos, paths and redeem scripts //for each blocktrail pub key, do fund discovery on batches of addresses foreach ($this->blocktrailPublicKeys as $keyIndex => $blocktrailPubKey) { $i = 0; do { if ($this->debug) { echo "\ngenerating {$increment} addresses using blocktrail key index {$keyIndex}\n"; } $addresses = $this->createBatchAddresses($i, $increment, $keyIndex); $totalAddressesGenerated += count($addresses); if ($this->debug) { echo "\nstarting fund discovery for {$increment} addresses"; } //get the unspent outputs for this batch of addresses $utxos = $this->utxoFinder->getUTXOs(array_keys($addresses)); //save the address utxos, along with relevant path and redeem script foreach ($utxos as $address => $outputs) { $addressUTXOs[$address] = array('path' => $addresses[$address]['path'], 'redeem' => $addresses[$address]['redeem'], 'utxos' => $outputs); $totalUTXOs += count($outputs); //add up the total utxo value for all addresses $totalBalance = array_reduce($outputs, function ($carry, $output) { return $carry += $output['value']; }, $totalBalance); if ($this->debug) { echo "\nfound " . count($outputs) . " unspent outputs in address {$address}"; } } //increment for next batch $i += $increment; } while (count($utxos) > 0); } if ($this->debug) { echo "\nfinished fund discovery: {$totalBalance} Satoshi (in {$totalUTXOs} outputs) found when searching {$totalAddressesGenerated} addresses"; } $this->sweepData = ['utxos' => $addressUTXOs, 'count' => $totalUTXOs, 'balance' => $totalBalance, 'addressesSearched' => $totalAddressesGenerated]; return $this->sweepData; }