-
-
Save ItsShadowl/c250ee540316bc4d306fdb0135ccf447 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* example script to receive webhook events for a wallet and forward the bitcoin to another address (by the mapping) | |
*/ | |
use BitWasp\BitcoinLib\RawTransaction; | |
use Blocktrail\SDK\Blocktrail; | |
use Blocktrail\SDK\BlocktrailSDK; | |
use Blocktrail\SDK\Connection\Exceptions\ObjectNotFound; | |
use Blocktrail\SDK\TransactionBuilder; | |
use Blocktrail\SDK\Wallet; | |
use Blocktrail\SDK\WalletInterface; | |
require_once __DIR__ . "/../vendor/autoload.php"; | |
/** | |
* easy debugging helper, both var_dump and error_log for w/e you are | |
* @param $m | |
*/ | |
function debug($m) { | |
var_dump($m); | |
error_log(json_encode($m)); | |
}; | |
// address map of old -> new addresses | |
// you could read JSON file | |
// $addressMap = json_decode(file_get_contents(__DIR__ . "address_map.json"), true); | |
$addressMap = [ | |
// "old" => "new", | |
"2NE51wGFR4dQYWAG6jUYTtnsAyDeBv3jUyV" => "2MvusSia19Yk19Rw8PjGVjj1TjvxcP1eT23", // example of my own wallet | |
]; | |
// init SDK with API key + secret | |
$testnet = true; | |
$client = new BlocktrailSDK("MY_APIKEY", "MY_APISECRET", "BTC", $testnet); | |
// wallet identifier and password for a little down the line | |
$walletIdentifier = "testyrgridwallet"; | |
$walletPassword = "testyrgridwallet"; | |
// read POST JSON | |
$json = file_get_contents("php://input"); | |
$data = json_decode($json, true); | |
// sanity check | |
if (!isset($data['network']) || !isset($data['event_type'])) { | |
throw new \Exception("Invalid request"); | |
} | |
// sanity check | |
if (($testnet && $data['network'] !== 'tBTC') || (!$testnet && $data['network'] !== 'BTC')) { | |
throw new \Exception("Invalid network"); | |
} | |
// sanity check | |
if ($data['event_type'] != "address-transactions") { | |
debug("event we don't care about, ignore!"); | |
exit(0); | |
} | |
$transaction = $data['data']; | |
$confirmations = $transaction['confirmations']; | |
$walletInfo = $data['wallet']; | |
$addressInfo = $data['addresses']; | |
// we should always have a webhook call for either unconfirmed or fist confirmed, ignore others | |
// it wouldn't hurt to replace this with something that keeps track if the transaction was already processed | |
// because then we don't have to try and spend it (blindly), see also the trycatch around the sending of the TX | |
if ($confirmations > 1) { | |
debug("> 1 confirmation, ignore!"); | |
exit(0); | |
} | |
// ignore outgoign txs | |
if ($walletInfo['balance'] <= 0) { | |
debug("Outgoing transaction, ignore!"); | |
exit(0); | |
} | |
if (count($walletInfo['addresses']) > 0) { | |
throw new \Exception("This is very weird, incoming transaction with multiple addresses owned by this wallet [{$transaction['hash']}]"); | |
} | |
// uncommit for easy debugging info | |
// debug(json_encode($data)); | |
// loop over all addresses that are part of the wallet | |
foreach ($walletInfo['addresses'] as $address) { | |
// check if address received BTC (balance change is positive) | |
$sum = $addressInfo[$address]; | |
if ($sum <= Blocktrail::BASE_FEE) { | |
throw new \Exception("TX that isn't work forwarding because it's less than the fee [{$transaction['hash']}]"); | |
} | |
if ($sum > 0) { | |
// check if we know a mapping for this address | |
if (!isset($addressMap[$address])) { | |
throw new \Exception("Address not in mapping [{$address}] for TX [{$transaction['hash']}]"); | |
} | |
// new address | |
$newAddress = $addressMap[$address]; | |
// filter out the outputs that are relevant (we don't care about the change) | |
$outputs = array_filter($transaction['outputs'], function($output) use($address) { return $output['address'] == $address; }); | |
// sanity check | |
if (count($outputs) == 0) { | |
throw new \Exception("Impossible"); | |
} | |
// make a TxBuilder so we can construct a custom TX | |
$txBuilder = new TransactionBuilder(); | |
// use the outputs of the TX as the inputs for the new TX | |
foreach ($outputs as $output) { | |
$txBuilder->spendOutput($transaction['hash'], $output['index'], $output['value'], $output['address']); | |
} | |
// use fixed BASE_FEE | |
$fee = Blocktrail::BASE_FEE; | |
// send total minus fee to new address | |
// alternatively you could hardcode an address of a completely seperate wallet for these funds | |
// when your webhook would support the old addresses still | |
$txBuilder->addRecipient($newAddress, $sum - $fee); | |
// fixed fee, so it won't do coinselection (which would probably cause change etc, to hard to deal with) | |
$txBuilder->setFee($fee); | |
// init wallet, need it now | |
$wallet = $client->initWallet([ | |
"identifier" => $walletIdentifier, | |
"passphrase" => $walletPassword | |
]); | |
// send | |
try { | |
$txHash = $wallet->sendTx($txBuilder, false); | |
debug($txHash); | |
exit(0); | |
} catch (\Exception $e) { | |
if ($confirmations === 1) { | |
// ignore, we probably failed to do the TX because we already did it when confirmations=0 | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment