Webhooks в биткойн-транзакциях - как применять бизнес-логику?
Я хочу начать принимать Биткойн на своем сайте.
Для этого я написал следующий фрагмент кода, но я действительно изо всех сил пытаюсь понять, как я могу реализовать правильную бизнес-логику после завершения транзакции.
Вот код:
<html>
<head>
<title>Pay with Bitcoin</title>
<script>
//Gets the URL of the Webpage and gets the price value of this transaction in USD.
//For simplicity Here the Value is passed in the URL.
//However in production you wanna use POST instead of GET.
const myUrl = window.location.href;
const url = new URL(myUrl);
const usdPrice = url.searchParams.get("price");
//This is the function where all the magin happens
const showQR = () => {
//URL of the api which will provide us with current BTC exchange rate
const apiUrl = "https://blockchain.info/ticker";
const hr = new XMLHttpRequest();
hr.open('GET', apiUrl, true);
hr.onreadystatechange = function(){
//Make sure the API sent a valid response
if(hr.readyState == 4){
let ticker = JSON.parse(hr.responseText);
//Get last BTC/USD exchange value from the API , then convert Price from USD to BTC
let BTCprice = ticker.USD.last;
let btcToPay = usdPrice / BTCprice;
//Make sure you have just 8 decimal points in your BTC price!!
btcToPay = btcToPay.toFixed(8);
//Use google API (or other...) to create the QR code. Pass on your btc public address and
//the amount (btc price) dynamically created. Message and label parameters can be dynamic too.
let qrurl = "https://chart.googleapis.com/chart?chs=250x250&cht=qr&chl=bitcoin:1BAnkZn1qW42uRTyG2sCRN9F5kgtfb5Bci?amount="+btcToPay+"%26label=CarRental%26message=BookingID123456";
//Populate the 'btc' DIV with QR code and other info...
document.getElementById('btc').innerHTML = "<img src=" +qrurl+"><br> <span class = 'greenMoney'>" + usdPrice + " usd / " + btcToPay + " BTC </span>";
}
}
hr.send();
};
</script>
</head>
<body onload = "showQR()">
<h1>Pay with BitCoin</h1>
<div id = "btc">
</div>
</body>
</html>
Этот код делает следующее:
Получает текущий курс доллара США / БТД с помощью API блокчейна.
берет цену в долларах США за URL и конвертирует ее в BTC
генерирует QR-код с помощью Google API.
Встраивает цену, этикетку и сообщение в QR-код
Оказывает QR-код в DIV
Я также настроил службу веб-перехвата, которая будет прослушивать новые транзакции, происходящие по указанному адресу кошелька. Затем производится обратный вызов на мой сервер посредством запроса POST.
Проблема в том, что метка и параметры сообщения, переданные в QR-код, не будут записаны в блокчейн.
Они просто удобные ссылки для клиента, чтобы напомнить ему, за что заплатила эта конкретная транзакция.
В результате обратный вызов на мой сервер практически бесполезен.
На самом деле, обратный вызов не возвращает ни идентификатора бронирования, ни какой-либо другой информации, которая могла бы помочь мне понять, кто за что заплатил. Излишне говорить, что в этом сценарии невозможна бизнес-логика: я не могу обновить статус заказа в своей БД, я не могу отправить подтверждение по электронной почте нужному клиенту.
Как я могу вставить соответствующую информацию (например, ID бронирования) в платеж BTC, в идеале через QR-код?
Если это возможно, как я могу получить эту информацию позже, когда мой сервер получит ответный звонок, информирующий меня о том, что был произведен новый платеж на мой BTC-кошелек?
2 ответа
@Raghav Sood спасибо за ваш вклад, который направил меня в правильном направлении.
Используя NodeJS/Express/MongoDB в бэкэнде, мне удалось реализовать решение, которым я хотел бы поделиться здесь.
Прежде чем начать, я хочу сделать большой отказ от ответственности: это решение не единственное, оно не самое лучшее, оно не самое быстрое и, вероятно, не самое элегантное.
В любом случае, это решение имеет то преимущество, что не полагается на пакетные решения третьих сторон. Это соответствует духу всей философии "без посредников" сообщества биткойнов. Самое главное, ваш XPub всегда остается на вашем сервере и НЕ используется совместно с какой-либо внешней службой, что, вероятно, является самым разумным подходом.
Сказав это, вот как можно показать клиентам динамические уникальные адреса BTC:
- Прежде всего, я установил счетчик, который отслеживает, сколько адресов btc было создано для клиентов из моего HD-кошелька.
Это важно, чтобы убедиться, что вы никогда не предоставляете клиентам один и тот же адрес дважды, что хорошо для конфиденциальности всех сторон, а также для реализации бизнес-логики в вашем приложении.
Для этого я сохраняю "значение счетчика" в моей БД. Каждый раз, когда кто-то посещает страницу оплаты BTC, это значение извлекается из mongo с помощью функции dealCount и присваивается переменной serialPay, которая равна значению, полученному из Mongo + 1. В бэкэнде код был бы что-то вроде этого:
`function dealCount(){`
return new Promise(function(resolve, reject){
Deal.find({_id: "ID_OF_OBJ_WHERE_YOU_STORE_COUNTER"}, function(err, data){
if(err){
console.log(err);
}
resolve(data[0].serialDeal + 1);
})
})
};
Полученное новое значение (которое впоследствии будет снова сохранено в Mongo для отслеживания созданных адресов) используется для генерации нового публичного адреса BTC для данного клиента. Если вы продолжите читать, вы увидите, как.
Для динамического создания новых публичных адресов требуется ключ xPub его или ее HD-кошелька. Если кто-то кодирует в NodeJS, есть пара библиотек (которые могут быть импортированы на сервер), которые довольно легко разрешат эту операцию: bitcoinjs-lib и / или bitcore-lib. Лично я выбрал Bitcore-lib, потому что здесь меньше зависимостей, и мне было легче усваивать вспомогательные материалы.
Codewise генерация адреса происходит следующим образом:
const bitcore = require('bitcore-lib');
app.post("/pay.html", urlencodedParser, function(req, res){
let serialPay = dealCount();
serialPay.then(function(serialPay){
const pub = new bitcore.HDPublicKey('INSERT_HERE_YOUR_XPUB_KEY');
let derivedHdPk = pub.derive('m/0/'+serialPay);
let derivedPk = derivedHdPk.publicKey;
let myDynAddress = new bitcore.Address(derivedPk);
res.render('pay', {myDynAddress: myDynAddress});
});
});
Затем, используя EJS в качестве движка шаблонов, я мог бы легко сделать динамический адрес получаемого биткойна во внешнем интерфейсе (/pay.ejs):
let myDynAddress = "<%=myDynAddress%>"; let qrurl = "https://chart.googleapis.com/chart?chs=250x250&cht=qr&chl=bitcoin:"+myDynAddress+"?amount="+btcToPay+"%26label=CarRental";
Это будет генерировать QR-код динамически. В оригинальном вопросе можно увидеть, как сделать это на веб-странице. В то же время следует также ввести функцию для сохранения обновленного счетчика "serialPay" обратно в БД.
На этом этапе следует только начать мониторинг входящих (неподтвержденных) платежей по сгенерированному динамическому адресу BTC. Простой способ сделать это - использовать API веб-сокета blockchain.info. Когда приходит платеж, все идет вперед, как предлагает @Raghav Sood: один проверяет входящую транзакцию, проверяя, что клиент заплатил нужную сумму по нужному адресу.
Теперь вы знаете, кто за что заплатил, и могут быть задействованы все виды бизнес-логики.
Короче говоря, вы не можете.
Принимая платежи, вы должны указать каждому счету новый адрес BTC. Таким образом, когда вы получаете уведомление о входящей транзакции, вы можете проверить адрес получателя, чтобы увидеть, какой счет оплачивается, и сравнить полученную сумму с ожидаемой суммой.
Заметка
Технически, вы можете встроить такие вещи, как идентификатор заказа, в OP_RETURN. Тем не менее, большинство кошельков не поддерживают такие транзакции, и любые пользователи, которые хотят заплатить вам с биржевого счета, не смогут это выполнить.