Author

Topic: 2 BTC Bounty: PHP / JSON-RPC Sweep Key Function (Read 1978 times)

legendary
Activity: 2088
Merit: 1015
I actually implemented a sweep address not sweep privkey as was orifinally posted however by PM he said that was an erro on his part it should have stated a sweep privkey as it does now, and and he sent me 0.5 BTC.

Here was my code for free use:
Code: (php)
/**
 * Take the entire Balance of Address A and send it to Address B
 *
 * @param jsonRPCClient $jsonrpc A valid jsonRPCClient connected to bitcoind
 * @param string $addrA Address to sweep
 * @param string $addrB Address to receive swept funds
 * @param int $fee Fee to be applied (satoshis), is computed as ($perkb * size in kb) if $fee == -1
 *  else it is applied directly
 * @param int $perkb Fee (satoshis) to be applied per kb of transaction size
 * @param int $minconf Minimum number of confirmations required to be swept
 * @return array Result contains 2 elements, success and either message or txid.
 *  If success == true then txid contains the transaction id else message contains the error
 */
function sweepBTC($jsonrpc, $addrA, $addrB, $fee = -1, $perkb = 10000, $minconf = 0) {
    $unspent = $jsonrpc->listunspent($minconf);
    $txinputs = array();
    $addrbalance = 0;
 
    foreach ($unspent as $value) {
        if ($value["address"] == $addrA) {
            $txinputs[] = array("txid" => $value["txid"],
                "vout" => $value["vout"]);
            $addrbalance += (int) round($value["amount"] * 1e8);
        }
    }
 
    if (count($txinputs) < 1) {
        return array("success" => false, "message" => "No unspent outputs available");
    }
 
// fee calculate by ($perkb * size in kb) following the formula at:
// http://bitcoin.stackexchange.com/questions/1195/how-to-calculate-transaction-size-before-sending
    if ($fee == -1)
        $fee = (int) max($perkb * floor((count($txinputs) * 148 + 44) / 1024), $perkb);
    else if ($fee < 0) {
        return array("succes" => false, "message" => "Fee must be non-negative");
    }
 
    $btcToSend = ($addrbalance - $fee);
    if ($btcToSend < 0) {
        return array("success" => false, "message" => "Not enough funds to cover fee");
    }
    $rawtx = $jsonrpc->createrawtransaction(
            $txinputs, array(
        $addrB => ($btcToSend / 1e8)));
 
    $signedtx = $jsonrpc->signrawtransaction($rawtx);
    if ($signedtx["Complete"] == 1) {
        $txid = $jsonrpc->sendrawtransaction($signedtx["hex"]);
    } else {
        return array("success" => false, "message" => "Oddly the transaction did not sign completely...");
    }
    return array("success" => true, "txid" => $txid);
}
sr. member
Activity: 376
Merit: 312
Can you say... nighty-night?
was a bit bored and cannot sleep (hope there are no major mistakes Shocked)... had not tested the code, usage with caution and on your own risk!

i think the most difficult part is done ^.-

guess bitspill uses importprivkey and this is no option if i get the task right

todo:
- generating public address from given private key needs to be added
- may the script transform into a function
- ... aaand errorhandling!

i'm posting the code public, so everyone can blame me, can improve the code and benefit from it and one can get the bounty for finishin' the work :x

requirements:
- bitcoind/bitcoin-qt >= 0.7
- php >= 5.2.0

Code:

// guess this part is already done ^.^
$require_once("oneoftheserpclibs");
$rpc=new jsonRPCClient(...);
//


// -- user inputs?
$privatekey="";
$publickey=""; // replacing later to generate publickey from privatekey
$sweep="";
// -- user inputs end


// -- settings
$fee_per_kb=0.0001;
$value_min=0; // mabe change from 0 to 0.00005430 due to 0.8.2?
// -- settings end


// -- main part
$unspent_data=json_decode(file_get_contents("http://blockchain.info/unspent?active=".$publickey),true); // you have to get the unspent data from somewhere, rescan is no option, so pull from somewhere else, in this case, blockchain.info

$txs=array();
$txs_s=array();
$value=0.0;
foreach(
$unspent_data AS $k=>$v) // now parse the unspent data and prepare to send ;)
{
$txs[]=array("txid"=>$v['tx_hash'],"vout"=>$v['tx_output_n']);
$txs_s[]=array("txid"=>$v['tx_hash'],"vout"=>$v['tx_output_n'],"scriptPubKey"=>$v['script']);
$value+=($v['value']*1e8);
}
$fee=$fee_per_kb*ceil((count($txs)*181+74)/1024); // very simple calculating size and fee, should be enough in this case
$value-=$fee;
$recipients=array($sweep=>$value);

if(
$value>$value_min&&!empty($txs)) // only checking if real sending value is greater then 0/min and if inputs are given before creating the transaction, sign' and sending
{
$rawtransaction=$rpc->createrawtransaction($txs,$recipients);
$signed_transaction=$rpc->signrawtransaction($rawtransaction,$txs_s,array($privatekey));
if($signed_transaction['complete']==1)
{
$rpc->sendrawtransaction($signed_transaction['hex']);
}
}
// -- main part end

?>


edit: few typos
legendary
Activity: 2088
Merit: 1015
Well, I feel it is mostly complete now and the fee is exposed as a parameter however if it is -1 then the fee is calculated based upon tx size.

Would you prefer I PM you, or post the code here publicly?
legendary
Activity: 2088
Merit: 1015
Given a sweep address, a sweep to address and a RPC connection to Bitcoin-Qt, this function must send all the coins to the sweep to address, paying the appropriate network fee.

1.5 BTC bounty.
1) By sweep you mean to take the entire balance of "Address A" and send it to "Address B", correct?
2) "Appropriate network fee" Would you like that exposed as a parameter to the method or calculated somehow based upon the size of the transaction?


As of right now I have a crude but functional implementation that needs some error checking and other improvements.
vip
Activity: 1316
Merit: 1043
👻
Given a private key, a sweep to address and a RPC connection to Bitcoin-Qt, this function must send all the coins to the sweep to address, paying the appropriate network fee.

1.5 2 BTC bounty. Note: Cannot make use of costly wallet reindex operations.
Jump to: