public function testDecodeRedeemScript() { // Random samples from txs in the blockchain $samples = ["5221032c6aa78662cc43a3bb0f8f850d0c45e18d0a49c61ec69db87e072c88d7a9b6e9210353581fd2fc745d17264af8cb8cd507d82c9658962567218965e750590e41c41e21024fe45dd4749347d281fd5348f56e883ee3a00903af899301ac47ba90f904854f53ae", "5141048ff228400b3056084121fa83658c43858e3826d59ddc6cfd033df80565f8cc96e09e26e6a2320958a999cb82030d781698176a591424cf4f66b5644e7c8e690a41040f63d3a4b5d797b8ceb443ae54a45b7bb0465a792844e104e31eda18f8a0b0b8f42adaac0002bac7aae6a5cd4106be45172463e9caf44aa567da486455063d1152ae", "524104664547a29ffc51db8d46377c1c6611914e11a9c36a83992e642b6c3aa1f0017eee1d77d6d0e4f3b82be92067b39d7f62fe2da7b680e3e306402bf53f8dd5ef04410496cb89ca7f8f244808b4a50ee80e9acd12f801d33646aa9a50eb4a6b550f6520b4204a79f0192a30fc8c7b0eef18d49b3b720373f6b2b928023ae4b463c2c4eb52ae", "522102c33586c016c66158f921c54e30628d682627839d0297f800050b981ab298b58a2102bd4d0115f28b4ac3122e89ebab628f1de2db0a3947721f2fe9b17f9b96e2204052ae", "524104192944fe1ecf2bb78174a282a3b7d3a457bb40993a6785853cfcedf5bb6f67fd453db59b4e2cfd864480c86d816b383b0be51f82444f7bca0cdaa12e002b25da4104738bcb941b0ca59dad113393c212be91b4bb648efce44567bd372ffac64c6f373d2d928a34c6d1d98fced6a6b03852fc592eef7534d23b801a714e11f1a061ac410491ccd85240d31e84e40586d0bf10a1f1e9d309bffac8e179534be2a28310e92c486d9c7e47ee76e23f6b6f390075e16cf08b6ce9c3d2383c5a3a20b6598d224e53ae", "52410453e1bb5aa30c3711ac64ca03a38d7f248db3b31a2559efa8a4cb6fa63b5356e9d2cb8c26b722d7f984cc51ba6bfceb2e5306249f6ba626e73de1d412f2e8d4594104be2c03fe4f9aa55dea54812822a563138b4c12651ce3d1161b246c47379838ae1f7a0df55e6b475c2cddd278bcd130898a21e319e1bc02da86876efb9fcb621c4104cf5189fa8b6457a5e06f652ef8666499574632bc5c75f51fb049dcc93638309f493594e4bd6b1d6ac92f6d77cc52db255b92f20749b237927fb2a60d7c887a1053ae", "5241048c1bbabfd38a9d462443e9bd99e133f512efa9548743ffb3f544dcc83b9b0356780796678519987ba04a054445e0cea2a60f1cafc1dbcc97c412338771b094374104bf5d3c29bad79db8f541b0d1095ef1f8ba4e8eda75936dcec81ac72599121b561f2b4ce9a2947cf0a5498888ee8e2a918c7e595da8fa1ae5b28df607e5fc29bb4104d79d37c0f322442bea954bb3fda3a97b24b113152a638316a1fbd44673e28967cefca7c3ed366ed41bbc0978dc308efab89f6e9010912d1e6c3fed0d4dc2b63d53ae", "5121031b9abc9a11a4a078509969f12de3129bf81060b001742e05cd8041a7e7402bcb51ae", "5241043a0f00454bdcd92698bebd22de0785c8dd190144115b3eced47f26796e24c3050faa3cb3b46a5a868a8f77f7f08ddda7c90952ca07bc18fc9765b8f0bc28cdd941044d7e454064678f032c6a845a986a41e20ae224a7843eb397637e7d1df2c80762b0a14d348cb2a4261cf83fba77d1e025a9eaaf251e1a23f9caabb4c9c5fba5314104ba5b7a9ce88ee36d8689e6a70e847b88d2ddcd12a008195f5b841f88485e14d6a3abc4120e721a50655ce3ba63606ba7ac927254f89ec3d0dea3bfe1d7b2797653ae", "5241046bcd91262b52419bdb0a88cc628e6eeed8ca7c60857a04be80c9cef320a775881d01b439cefc6e814f713c753be596fb65b5575f9e99583cd50776474e80adc14104b730f446201772dbc67d39f72fe9ef2e966066718070a4248874fb237a325dfa43073a893f95ae713d40194bac5d6cb23d25616e0966286c9c7416afe7214ac84104b31a45c0362e0c56e868bb7563334b3b35eb0f4af810648e45e365c46eaf983a155b6ec834db5143a7df47780fbf7e9f6ac5c3d45837b6c76b0c9c4c864feee453ae", "524104f10d42e5a5dc24dabe524dc305f9deab2c5b58c42aa83833d1d2ad38c9b796b4756a99e60bfee19e92424f3aa919fb63377b6d8d35d091d6a5de62b58b8c8d7721025563ee4b549f5a7d3dfb046a088815c69ebd44b389a78342ccb01e77d89465a752ae", "522102c48bf0c25bf78fbe98988ef8f27ee05284f79c550e987a88e1237872c030ab8021026f6020210361586f02c93cfb926fed3d240b7f11b1a5694b36c826561abd3932210352057bbf5c024edd3630606689956c52104150d1c494b1d92ca6c7243d5eeb7453ae", "522102d7297e56bc410c2d1671cd2694686400f59061bef1bbb6f7e3269dacbbdce53e2102421a4efafabd2534116deb6c00a01831de71c62c53a5e718b852ccd81a7ff98c52ae", "522102d7297e56bc410c2d1671cd2694686400f59061bef1bbb6f7e3269dacbbdce53e2102421a4efafabd2534116deb6c00a01831de71c62c53a5e718b852ccd81a7ff98c52ae", "52210374763369da3dca422b64e13ae1cf81a5f68dd09a1efcd463b5511fe7a436207a21021d7e25870057383faad795f651b3f5844c4d3ebb1e3a31e444e6a21d9af371642102c5463df6e77f7f659d123ca19e079ef9ec08e1ddfa4a1bcb4814902b2b1ad41c53ae", "5241046dae34916bec595e73b3fabfd1aad2158994fee1a5bc19216654dc49b47f1976a26d7a6d3c7b713f8650121812253a206c4cd7f1e7b453e8e700c720e99c60564104fcb3a8fd045eb2c77a45fdfed73317c22b4ab40de5950c944ff8b1cf45eb83aaafc8d987fe1706d10febc6277223569e0df10881b8cea2435b4fa3bdabf41ad021036c06d0a475646980d4ede31b6b4864946fe7fb54fa15102b03ac16a56c4300f053ae", "524104d403a9ec23cb289734645337a079c636ecc47b6015ebd88e972741948ddd65a708f8238f1da4b8f70945ae57288a4bc406e3811a0b83b4e610565cc83a5faff741046c82c6671ada6c430d8ea81b27ecae04fa9f0b4ab14bcceb89c589ea0d7b1919565221ef6c2004a6204f1d6d616eb770c13dbda3cdf271f2ae6fe5a654b5a42e2102e3929380fccb603649a8dd775ec2b1e81748b2749503e039530330f1a5b448bf53ae", "5221039bf1c1ec550815dee677d1b391a03f5f501abe6fd9817b2486bc03aa7ae038d8410437d0fd54cbbe8d4e6bd12d19b1c863d3cfbce71c4b31541546685c090d9572a2d2f5f30c58d45c7141cf29b7fe83002f29abccc9c290b7dba6eed9e9d773d1bc2102521e92a6b26db346cb8e2a27ceb2ec83905f3f8d3f8d52634c82c3ad8d0f188a53ae"]; foreach ($samples as $sample) { $raw = RawTransaction::decode_redeem_script($sample); $this->assertTrue(is_array($raw)); } }
<?php use BitWasp\BitcoinLib\BitcoinLib; use BitWasp\BitcoinLib\RawTransaction; require_once __DIR__ . '/../vendor/autoload.php'; while (!isset($redeem_script)) { echo "Enter redeem script: "; $line = trim(fgets(STDIN)); $decode_redeem_script = RawTransaction::decode_redeem_script($line); if ($decode_redeem_script == FALSE) { echo "[ERROR]- Not a valid script!\n"; unset($decode_redeem_script); } else { $redeem_script = $line; echo "Learned about {$decode_redeem_script['m']} of {$decode_redeem_script['n']} address: " . BitcoinLib::public_key_to_address($redeem_script, '05') . "\n"; } } echo "Enter WIF encoded private keys: \n (1): "; $private_keys = array(); while ("\n" != ($line = fgets(STDIN))) { $line = trim($line); $t = BitcoinLib::validate_WIF($line, '80'); var_dump($t); if (BitcoinLib::validate_WIF($line, '80') == TRUE) { $private_keys[] = $line; } else { echo "Not a valid private key.\n"; } echo " (" . (count($private_keys) + 1) . "): "; } // Initialize wallet
/** * Details * Buyer URI: purchases/details/<order_id> * Vendor URI: orders/details/<order_id> * Admin URI: admin/orders/<order_id> * * Order details page. Shows buyer/vendor/admin the details of the * the order. * * @param int $order_id */ public function details($order_id) { if (!(is_numeric($order_id) && $order_id >= 0)) { redirect(''); } $data['order'] = $this->order_model->get($order_id); // no restriction on buyer/vendor if ($data['order'] == FALSE) { redirect(''); } // Work out if the user is allowed to view this order. if (!$this->current_user->user_role == 'Admin' && !($this->current_user->user_id == $data['order']['buyer']['id']) && !($this->current_user->user_id == $data['order']['vendor']['id'])) { redirect(''); } // Only allow access when the order is confirmed by the buyer. if ($data['order']['progress'] == '0') { redirect(''); } if ($this->current_user->user_role == 'Buyer') { $data['action_page'] = 'purchases/details/' . $order_id; $data['cancel_page'] = 'purchases'; } else { if ($this->current_user->user_role == 'Vendor') { $data['action_page'] = 'orders/details/' . $order_id; $data['cancel_page'] = 'orders'; } else { if ($this->current_user->user_role == 'Admin') { $data['action_page'] = 'admin/order/' . $order_id; $data['cancel_page'] = 'admin/orders'; } } } $this->load->model('transaction_cache_model'); $this->load->model('bip32_model'); $this->load->model('review_model'); $child_key_id = $data['order'][strtolower($this->current_user->user_role) . '_public_key']; $data['my_multisig_key'] = $this->bip32_model->get_child_key($child_key_id); $data['wallet_salt'] = $this->users_model->wallet_salt($this->current_user->user_id); $this->load->library('bw_bitcoin'); $html = $this->bw_bitcoin->js_html($data['order']['redeemScript'], $data['order']['unsigned_transaction']); if (is_array($data['my_multisig_key'])) { $data['signing_info'] = array('parent_extended_public_key' => $data['my_multisig_key']['parent_extended_public_key'], 'extended_public_key' => $data['my_multisig_key']['extended_public_key'], 'bip32_provider' => $data['my_multisig_key']['provider'], 'full_key_index' => "m/0'/0/" . $data['my_multisig_key']['key_index'], 'key_index' => "m/0'/0/" . $data['my_multisig_key']['key_index'], 'public_key' => $data['my_multisig_key']['public_key'], 'partially_signed_transaction' => $data['order']['partially_signed_transaction'], 'unsigned_transaction' => $data['order']['unsigned_transaction'], 'wallet_salt' => $data['wallet_salt'], 'crafted_html' => $html); $ident = strtolower($data['my_multisig_key']['provider']); $this->_partial("sign_form_output", "orders/details_form_" . $ident); if ($ident == 'js') { $data['header_meta'] = $this->load->view('orders/add_signature_js', $data['signing_info'], TRUE); $this->load->model('users_model'); } elseif ($ident == 'onchain') { $this->load->library('onchainlib'); $tx_crc = substr(hash('sha256', $data['order']['partially_signed_transaction'] == '' ? $data['order']['unsigned_transaction'] : $data['order']['partially_signed_transaction']), 0, 8); $data['onchain_sign'] = $this->onchainlib->sign_request($data['order']['id'], $tx_crc); } } // Only allow a vendor to refund, if the progress is either 3 or 4 (not yet dispatched) $data['can_refund'] = ($this->current_user->user_role == 'Vendor' and in_array($data['order']['progress'], array('3', '4'))); $data['display_sign_form'] = (bool) (($data['order']['vendor_selected_upfront'] == '1' or $data['order']['vendor_selected_escrow'] == '0') and $data['order']['progress'] == '3' && $this->current_user->user_role == 'Buyer' or $data['order']['progress'] == '4' && $this->current_user->user_role == 'Vendor' or ($data['order']['vendor_selected_escrow'] == '1' and $data['order']['vendor_selected_upfront'] == '0' and $data['order']['progress'] == '4' && $this->current_user->user_role == 'Vendor' or $data['order']['progress'] == '5' && $this->current_user->user_role == 'Buyer') or ($data['order']['progress'] == '6' and $data['order']['partially_signed_transaction'] == '' or $data['order']['partially_signed_transaction'] !== '' and $data['order']['partially_signing_user_id'] !== $this->current_user->user_id) or ($data['order']['progress'] == '8' and $data['order']['partially_signed_transaction'] == '' or $data['order']['partially_signed_transaction'] !== '' and $data['order']['partially_signing_user_id'] !== $this->current_user->user_id)); $data['display_sign_msg'] = $data['order']['partially_signed_transaction'] == '' ? 'Please add first signature.' : 'Please sign to complete transaction.'; // Only allow access to the form handling script if the form is allowed to be displayed. if ($data['display_sign_form'] == TRUE) { // JS if ($this->input->post('submit_js_signed_transaction') == 'Submit Transaction') { if ($this->form_validation->run('submit_js_signed_transaction') == TRUE) { $check = $this->bw_bitcoin->handle_order_tx_submission($data['order'], $this->input->post('js_transaction'), $data['my_multisig_key']); if (is_string($check)) { $data['invalid_transaction_error'] = $check; } else { if ($check == TRUE) { if (strlen($data['order']['partially_signed_transaction']) > 0) { $this->current_user->set_return_message('Transaction has been submitted, and will be processed shortly.', 'success'); redirect($data['action_page']); } else { if ($data['order']['progress'] == '3') { // Buyer must sign early before vendor dispatches. $update = array('partially_signed_transaction' => $this->input->post('js_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time()); $this->order_model->progress_order($order_id, '3', '4', $update); } else { if ($data['order']['progress'] == '4') { // Vendor indicates they have dispatched. $update = array('partially_signed_transaction' => $this->input->post('js_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time(), 'dispatched_time' => time(), 'dispatched' => '1'); $this->order_model->progress_order($order_id, '4', '5', $update); } else { if ($data['order']['progress'] == '6') { $update = array('partially_signed_transaction' => $this->input->post('js_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time()); $this->order_model->update_order($order_id, $update); } else { if ($data['order']['progress'] == '8') { $update = array('partially_signed_transaction' => $this->input->post('js_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time()); $this->order_model->update_order($order_id, $update); } } } } $this->current_user->set_return_message('Your partially signed transaction has been saved!', 'success'); redirect($data['action_page']); } } } } } // Manual if ($this->input->post('submit_signed_transaction') == 'Submit Transaction') { if ($this->form_validation->run('input_transaction') == TRUE) { $validate = $this->bw_bitcoin->handle_order_tx_submission($data['order'], $this->input->post('partially_signed_transaction'), $data['my_multisig_key']); if (is_string($validate)) { $data['invalid_transaction_error'] = $validate; } else { if ($validate == TRUE) { if (strlen($data['order']['partially_signed_transaction']) > 0) { $this->current_user->set_return_message('Transaction has been submitted, and will be processed shortly.', 'success'); redirect($data['action_page']); } else { if ($data['order']['progress'] == '3') { // Buyer must sign early before vendor dispatches. $update = array('partially_signed_transaction' => $this->input->post('partially_signed_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time()); $this->order_model->progress_order($order_id, '3', '4', $update); } else { if ($data['order']['progress'] == '4') { // Vendor indicates they have dispatched. $update = array('partially_signed_transaction' => $this->input->post('partially_signed_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time(), 'dispatched_time' => time(), 'dispatched' => '1'); $this->order_model->progress_order($order_id, '4', '5', $update); } else { if ($data['order']['progress'] == '6') { $update = array('partially_signed_transaction' => $this->input->post('partially_signed_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time()); $this->order_model->update_order($order_id, $update); } else { if ($data['order']['progress'] == '8') { $update = array('partially_signed_transaction' => $this->input->post('partially_signed_transaction'), 'partially_signing_user_id' => $this->current_user->user_id, 'partially_signed_time' => time()); $this->order_model->update_order($order_id, $update); } } } } $this->current_user->set_return_message('Your partially signed transaction has been saved!', 'success'); redirect($data['action_page']); } } } } } } $data['redeem_script'] = RawTransaction::decode_redeem_script($data['order']['redeemScript']); $data['addrs'] = array($data['order']['buyer_payout'] => 'buyer', $data['order']['vendor_payout'] => 'vendor'); if (isset($data['order']['public_keys']['admin'])) { $data['addrs'][BitcoinLib::public_key_to_address($data['order']['public_keys']['admin']['public_key'], $this->bw_config->currencies[0]['crypto_magic_byte'])] = 'admin'; } if (strlen($data['order']['partially_signed_transaction']) > 0) { $data['raw_tx'] = RawTransaction::decode($data['order']['partially_signed_transaction']); $data['signer'] = $this->accounts_model->get(array('id' => $data['order']['partially_signing_user_id'])); } else { if (strlen($data['order']['unsigned_transaction']) > 0) { $data['raw_tx'] = RawTransaction::decode($data['order']['unsigned_transaction']); } } $checkStrangeAddress = function () use($data) { $tx_addrs = array(); foreach ($data['raw_tx']['vout'] as $vout) { $tx_addrs[] = $vout['scriptPubKey']['addresses'][0]; } return count($tx_addrs) != count(array_intersect($tx_addrs, array_keys($data['addrs']))); }; $data['strange_address'] = isset($data['raw_tx']) ? $checkStrangeAddress() : FALSE; $data['fees']['shipping_cost'] = $data['order']['shipping_costs']; $data['fees']['fee'] = $data['order']['fees']; $data['fees']['escrow_fees'] = $data['order']['extra_fees']; $data['fees']['total'] = $data['order']['shipping_costs'] + $data['order']['fees']; if ($this->current_user->user_role == 'Buyer' && $data['order']['paid_time'] == '') { $this->load->library('ciqrcode'); $data['payment_url'] = "bitcoin:{$data['order']['address']}?amount={$data['order']['order_price']}&message=Order+{$data['order']['id']}&label=Order+{$data['order']['id']}"; $data['qr'] = $this->ciqrcode->generate_base64(array('data' => $data['payment_url'])); } $data['page'] = 'orders/details'; $data['title'] = 'Order Details: #' . $data['order']['id']; $this->_render($data['page'], $data); }
public function js_html($redeem_script, $raw_transaction) { if (strlen($redeem_script) == '0' || strlen($raw_transaction) == '0') { return ''; } $this->CI->load->model('transaction_cache_model'); $decode_rs = \BitWasp\BitcoinLib\RawTransaction::decode_redeem_script($redeem_script); $pubkey_list = ''; foreach ($decode_rs['keys'] as $i => $key) { $pubkey_list .= ' "' . $key . '"' . ($i < 2 ? ',' : '') . "\n"; } $p2sh_info = \BitWasp\BitcoinLib\RawTransaction::create_multisig(2, $decode_rs['keys']); $decode_tx = \BitWasp\BitcoinLib\RawTransaction::decode($raw_transaction); $utxos = ""; foreach ($decode_tx['vin'] as $vin => $input) { $tx_info = $this->CI->transaction_cache_model->get_payment($input['txid']); $utxos .= "\n{\n address: '{$p2sh_info['address']}',\n txid: '{$tx_info['tx_id']}',\n vout: {$tx_info['vout']},\n scriptPubKey: '{$tx_info['pkScript']}',\n confirmations: 10,\n amount: " . $tx_info['value'] . "\n}" . ($vin < count($decode_tx['vin']) - 1 ? ',' : '') . "\n"; //".($current_block-$tx_info['block_height']).", } $outs = ''; foreach ($decode_tx['vout'] as $vout => $output) { $outs .= '{ address: "' . $output['scriptPubKey']['addresses'][0] . '", amount: ' . $output['value'] . "\n}" . ($vout < count($decode_tx['vout']) - 1 ? ',' : ''); } $json = "\nvar pubkeys = [\n{$pubkey_list}\n];\n\nvar opts = {\n nreq: 2,\n pubkeys: pubkeys\n};\n\nvar serialized_pubkeys = [];\nfor (var i=0; i<3; i++) {\n serialized_pubkeys.push(new bitcore.buffertools.Buffer(opts.pubkeys[i],'hex'));\n}\n\nvar script = bitcore.Script.createMultisig(opts.nreq, serialized_pubkeys, {noSorting: true});\nvar hash = bitcore.util.sha256ripe160(script.getBuffer());\n\n\nvar p2shScript = script.serialize().toString('hex');\nvar p2shAddress = new bitcore.Address.fromScript(p2shScript).toString();\nconsole.log('got address: '+p2shAddress);\n\nvar utxos = [\n{$utxos}\n];\n\nvar outs = [\n{$outs}\n];\n\nvar hashMap = {};\nhashMap[p2shAddress] = p2shScript;\n "; return $json; }