예제 #1
0
 /**
  * this test requires / asumes that the test wallet it uses contains a balance
  *
  * we keep the wallet topped off with some coins,
  * but if some funny guy ever empties it or if you use your own API key to run the test then it needs to be topped off again
  *
  * @throws \Exception
  */
 public function testWalletTransaction()
 {
     $client = $this->setupBlocktrailSDK();
     /** @var Wallet $wallet */
     $wallet = $client->initWallet(["identifier" => "unittest-transaction", "passphrase" => "password"]);
     $this->assertEquals("give pause forget seed dance crawl situate hole keen", $wallet->getPrimaryMnemonic());
     $this->assertEquals("unittest-transaction", $wallet->getIdentifier());
     $this->assertEquals("M/9999'", $wallet->getBlocktrailPublicKeys()[9999][1]);
     $this->assertEquals("tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ", $wallet->getBlocktrailPublicKeys()[9999][0]);
     $this->assertEquals("tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ", $wallet->getBlocktrailPublicKey("m/9999'")->key());
     $this->assertEquals("tpubD9q6vq9zdP3gbhpjs7n2TRvT7h4PeBhxg1Kv9jEc1XAss7429VenxvQTsJaZhzTk54gnsHRpgeeNMbm1QTag4Wf1QpQ3gy221GDuUCxgfeZ", $wallet->getBlocktrailPublicKey("M/9999'")->key());
     list($confirmed, $unconfirmed) = $wallet->getBalance();
     $this->assertGreaterThan(0, $confirmed + $unconfirmed, "positive unconfirmed balance");
     $this->assertGreaterThan(0, $confirmed, "positive confirmed balance");
     list($path, $address) = $wallet->getNewAddressPair();
     $this->assertTrue(strpos($path, "M/9999'/0/") === 0);
     $this->assertTrue(BitcoinLib::validate_address($address, false, null));
     ///*
     $value = BlocktrailSDK::toSatoshi(0.0002);
     $txHash = $wallet->pay([$address => $value], null, false, true, Wallet::FEE_STRATEGY_BASE_FEE);
     $this->assertTrue(!!$txHash);
     sleep(1);
     // sleep to wait for the TX to be processed
     try {
         $tx = $client->transaction($txHash);
     } catch (ObjectNotFound $e) {
         $this->fail("404 for tx[{$txHash}] [" . gmdate('Y-m-d H:i:s') . "]");
     }
     $this->assertTrue(!!$tx, "check for tx[{$txHash}] [" . gmdate('Y-m-d H:i:s') . "]");
     $this->assertEquals($txHash, $tx['hash']);
     $this->assertEquals(BlocktrailSDK::toSatoshi(0.0001), $tx['total_fee']);
     $this->assertTrue(count($tx['outputs']) <= 2);
     $this->assertTrue(in_array($value, array_column($tx['outputs'], 'value')));
     //*/
     /*
      * do another TX but with a LOW_PRIORITY_FEE
      */
     $value = BlocktrailSDK::toSatoshi(0.0001);
     $txHash = $wallet->pay([$address => $value], null, false, true, Wallet::FEE_STRATEGY_LOW_PRIORITY);
     $this->assertTrue(!!$txHash);
     sleep(1);
     // sleep to wait for the TX to be processed
     try {
         $tx = $client->transaction($txHash);
     } catch (ObjectNotFound $e) {
         $this->fail("404 for tx[{$txHash}] [" . gmdate('Y-m-d H:i:s') . "]");
     }
     $this->assertTrue(!!$tx, "check for tx[{$txHash}] [" . gmdate('Y-m-d H:i:s') . "]");
     $this->assertEquals($txHash, $tx['hash']);
     $this->assertTrue(count($tx['outputs']) <= 2);
     $this->assertTrue(in_array($value, array_column($tx['outputs'], 'value')));
     /*
      * do another TX but with a custom - high - fee
      */
     $value = BlocktrailSDK::toSatoshi(0.0001);
     $forceFee = BlocktrailSDK::toSatoshi(0.001);
     $txHash = $wallet->pay([$address => $value], null, false, true, Wallet::FEE_STRATEGY_BASE_FEE, $forceFee);
     $this->assertTrue(!!$txHash);
     sleep(1);
     // sleep to wait for the TX to be processed
     try {
         $tx = $client->transaction($txHash);
     } catch (ObjectNotFound $e) {
         $this->fail("404 for tx[{$txHash}] [" . gmdate('Y-m-d H:i:s') . "]");
     }
     $this->assertTrue(!!$tx, "check for tx[{$txHash}] [" . gmdate('Y-m-d H:i:s') . "]");
     $this->assertEquals($txHash, $tx['hash']);
     $this->assertEquals($forceFee, $tx['total_fee']);
     $this->assertTrue(count($tx['outputs']) <= 2);
     $this->assertTrue(in_array($value, array_column($tx['outputs'], 'value')));
     /*
      * do another TX with OP_RETURN using TxBuilder
      */
     $value = BlocktrailSDK::toSatoshi(0.0002);
     $moon = "MOOOOOOOOOOOOON!";
     $txBuilder = new TransactionBuilder();
     $txBuilder->randomizeChangeOutput(false);
     $txBuilder->addRecipient($address, $value);
     $txBuilder->addOpReturn($moon);
     $txBuilder = $wallet->coinSelectionForTxBuilder($txBuilder);
     $txHash = $wallet->sendTx($txBuilder);
     $this->assertTrue(!!$txHash);
     sleep(1);
     // sleep to wait for the TX to be processed
     try {
         $tx = $client->transaction($txHash);
     } catch (ObjectNotFound $e) {
         $this->fail("404 for tx[{$txHash}] [" . gmdate('Y-m-d H:i:s') . "]");
     }
     $this->assertTrue(!!$tx, "check for tx[{$txHash}] [" . gmdate('Y-m-d H:i:s') . "]");
     $this->assertEquals($txHash, $tx['hash']);
     $this->assertTrue(count($tx['outputs']) <= 3);
     $this->assertEquals($value, $tx['outputs'][0]['value']);
     $this->assertEquals(0, $tx['outputs'][1]['value']);
     $this->assertEquals("6a" . "10" . bin2hex($moon), $tx['outputs'][1]['script_hex']);
 }
예제 #2
0
 /**
  * create, sign and send a transaction
  *
  * @param array     $outputs            [address => value, ] or [[address, value], ] or [['address' => address, 'value' => value], ] coins to send
  *                                      value should be INT
  * @param string    $changeAddress      change address to use (autogenerated if NULL)
  * @param bool      $allowZeroConf
  * @param bool      $randomizeChangeIdx randomize the location of the change (for increased privacy / anonimity)
  * @param null|int  $forceFee           set a fixed fee instead of automatically calculating the correct fee, not recommended!
  * @return string the txid / transaction hash
  * @throws \Exception
  */
 public function pay(array $outputs, $changeAddress = null, $allowZeroConf = false, $randomizeChangeIdx = true, $forceFee = null)
 {
     if ($this->locked) {
         throw new \Exception("Wallet needs to be unlocked to pay");
     }
     $outputs = self::normalizeOutputsStruct($outputs);
     $txBuilder = new TransactionBuilder();
     $txBuilder->randomizeChangeOutput($randomizeChangeIdx);
     foreach ($outputs as $output) {
         $txBuilder->addRecipient($output['address'], $output['value']);
     }
     $this->coinSelectionForTxBuilder($txBuilder, true, $allowZeroConf, $forceFee);
     $apiCheckFee = $forceFee === null;
     return $this->sendTx($txBuilder, $apiCheckFee);
 }