Skip to content

Commit

Permalink
add forceFee to Wallet::pay
Browse files Browse the repository at this point in the history
  • Loading branch information
rubensayshi committed Jun 25, 2015
1 parent 81b2c79 commit 4d8b064
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 18 deletions.
5 changes: 5 additions & 0 deletions src/TransactionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ public function shouldRandomizeChangeOuput() {
* @return $this
*/
public function setFee($value) {
// using this 'dirty' way of checking for a float since there's no other reliable way in PHP
if (!is_int($value)) {
throw new \Exception("Fee should be in Satoshis (int) - can be 0");
}

$this->fee = $value;

return $this;
Expand Down
36 changes: 23 additions & 13 deletions src/Wallet.php
Original file line number Diff line number Diff line change
Expand Up @@ -498,10 +498,11 @@ public function doDiscovery($gap = 200) {
* @param string $changeAddress (optional) change address to use (autogenerated if NULL)
* @param bool $allowZeroConf
* @param bool $randomizeChangeIdx randomize the location of the change (for increased privacy / anonimity)
* @return string the txid / transaction hash
* @param 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) {
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");
}
Expand All @@ -517,6 +518,15 @@ public function pay(array $outputs, $changeAddress = null, $allowZeroConf = fals
$txBuilder = new TransactionBuilder();
$txBuilder->randomizeChangeOutput($randomizeChangeIdx);

if ($forceFee !== null) {
$txBuilder->setFee($forceFee);
$apiCheckFee = false;
} else {
$txBuilder->validateChange($change);
$txBuilder->validateFee($fee);
$apiCheckFee = true;
}

foreach ($utxos as $utxo) {
$txBuilder->spendOutput($utxo['hash'], $utxo['idx'], $utxo['value'], $utxo['address'], $utxo['scriptpubkey_hex'], $utxo['path'], $utxo['redeem_script']);
}
Expand All @@ -525,10 +535,7 @@ public function pay(array $outputs, $changeAddress = null, $allowZeroConf = fals
$txBuilder->addRecipient($output['address'], $output['value']);
}

$txBuilder->validateChange($change);
$txBuilder->validateFee($fee);

return $this->sendTx($txBuilder);
return $this->sendTx($txBuilder, $apiCheckFee);
}

/**
Expand Down Expand Up @@ -626,8 +633,9 @@ public function buildTx(TransactionBuilder $txBuilder) {

// if change is not dust we need to add a change output
if ($change > Blocktrail::DUST) {
$changeIdx = count($send);
$changeAddress = $txBuilder->getChangeAddress() ?: $this->getNewAddress();
$send[$changeAddress] = $change;
$send[$changeIdx] = ['address' => $changeAddress, 'value' => $change];
} else {
// if change is dust we do nothing (implicitly it's added to the fee)
$change = 0;
Expand Down Expand Up @@ -701,26 +709,28 @@ public function buildTx(TransactionBuilder $txBuilder) {
* create, sign and send transction based on TransactionBuilder
*
* @param TransactionBuilder $txBuilder
* @param bool $apiCheckFee let the API check if the fee is correct
* @return string
* @throws \Exception
*/
public function sendTx(TransactionBuilder $txBuilder) {
public function sendTx(TransactionBuilder $txBuilder, $apiCheckFee = true) {
list($inputs, $outputs) = $this->buildTx($txBuilder);

return $this->_sendTx($inputs, $outputs);
return $this->_sendTx($inputs, $outputs, $apiCheckFee);
}

/**
* !! INTERNAL METHOD !!
* create, sign and send transction based on inputs and outputs
*
* @param $inputs
* @param $outputs
* @param $inputs
* @param $outputs
* @param bool $apiCheckFee let the API check if the fee is correct
* @return string
* @throws \Exception
* @internal
*/
public function _sendTx($inputs, $outputs) {
public function _sendTx($inputs, $outputs, $apiCheckFee = true) {
if ($this->locked) {
throw new \Exception("Wallet needs to be unlocked to pay");
}
Expand All @@ -740,7 +750,7 @@ public function _sendTx($inputs, $outputs) {
}

// send the transaction
$finished = $this->sendTransaction($signed['hex'], array_column($inputs, 'path'), true);
$finished = $this->sendTransaction($signed['hex'], array_column($inputs, 'path'), $apiCheckFee);

return $finished;
}
Expand Down
6 changes: 4 additions & 2 deletions src/WalletInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,10 @@ public function doDiscovery($gap = 200);
* @param string $changeAddress (optional) change address to use (autogenerated if NULL)
* @param bool $allowZeroConf
* @param bool $randomizeChangeIdx randomize the location of the change (for increased privacy / anonimity)
* @param int $forceFee set a fixed fee instead of automatically calculating the correct fee, not recommended!
* @return string the txid / transaction hash
*/
public function pay(array $outputs, $changeAddress = null, $allowZeroConf = false, $randomizeChangeIdx = true);
public function pay(array $outputs, $changeAddress = null, $allowZeroConf = false, $randomizeChangeIdx = true, $forceFee = null);

/**
* build inputs and outputs lists for TransactionBuilder
Expand All @@ -162,9 +163,10 @@ public function buildTx(TransactionBuilder $txBuilder);
* create, sign and send transction based on TransactionBuilder
*
* @param TransactionBuilder $txBuilder
* @param bool $apiCheckFee let the API check if the fee is correct
* @return string
*/
public function sendTx(TransactionBuilder $txBuilder);
public function sendTx(TransactionBuilder $txBuilder, $apiCheckFee = true);

/**
* delete the wallet
Expand Down
27 changes: 24 additions & 3 deletions tests/WalletTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,29 @@ public function testWalletTransaction() {
$this->assertTrue(BitcoinLib::validate_address($address, false, null));

$value = BlocktrailSDK::toSatoshi(0.0002);
$txHash = $wallet->pay([
$address => $value,
]);
$txHash = $wallet->pay([$address => $value,]);

$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 custom fee
*/
$value = BlocktrailSDK::toSatoshi(0.0002);
$txHash = $wallet->pay([$address => $value,], null, false, true, BlocktrailSDK::toSatoshi(0.0003));

$this->assertTrue(!!$txHash);

Expand All @@ -272,6 +292,7 @@ public function testWalletTransaction() {

$this->assertTrue(!!$tx, "check for tx[{$txHash}] [" . gmdate('Y-m-d H:i:s') . "]");
$this->assertEquals($txHash, $tx['hash']);
$this->assertEquals(BlocktrailSDK::toSatoshi(0.0003), $tx['total_fee']);
$this->assertTrue(count($tx['outputs']) <= 2);
$this->assertTrue(in_array($value, array_column($tx['outputs'], 'value')));
}
Expand Down

0 comments on commit 4d8b064

Please sign in to comment.