[Кодинг] Простой приём средств в Bitcoin
matrix
Мы будем рассматривать простой вариант системы приёма платежей, где имеется определённый список bincoin адресов, которые служат для получения монеты.
Почему именно такое решение, а не установка локального bitcoin core и выделение каждому пользователю своего адреса на пополнение? В первую очередь некоторая безопасность от слива монеты. Все адреса вы вставляете сами, и приватные ключи только у вас. На сервере находятся только адреса. Есть еще небольшие бонусы в виде того, что человек видит, что ранее кто-то платил и повышается рейтинг доверия. Еще мелочь, но когда на ресурсе 100500 регистраций, то нет нужды работать с 100500 адресами для дальнейшего управления монетой.
Пожалуй, начнём.
Сразу озвучим основное условие - система работает через API сайта chain.so. Можно достаточно легко перевести на любой другой сервис - всего лишь изменить запросы в соответствии с их API.
Для начала нам понадобится MySQL (MariaDB) сервер, где мы создадим таблицу, которая будет "вести учёт" входных финансовых потоков.
Основные поля, которые нам нужны, это индекс платежа, кто платит, сумма в биткоинах, сумма в долларах, статус, id транзакции и еще несколько вспомогательных полей. К примеру вот такой вариант вполне подойдёт:
CREATE TABLE `pays` ( `idx` int(11) NOT NULL, `user` int(11) NOT NULL DEFAULT '0', `summ_btc` decimal(16,8) NOT NULL DEFAULT '0.00000000', `summ_usd` decimal(10,2) NOT NULL DEFAULT '0.00', `date_add` timestamp NULL DEFAULT NULL, `status` tinyint(4) NOT NULL DEFAULT '0', `address` char(50) DEFAULT NULL, `transaction_btc` varchar(250) DEFAULT NULL, `date_val` timestamp NULL DEFAULT NULL, `text_` varchar(1024) DEFAULT NULL, `time_` bigint(20) NOT NULL DEFAULT '0', `kurs` decimal(10,2) NOT NULL DEFAULT '0.00' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `pays` ADD PRIMARY KEY (`idx`), ADD UNIQUE KEY `transaction_btc` (`transaction_btc`); ALTER TABLE `pays` MODIFY `idx` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;
Создадим дополнительную таблицу, где будут храниться наши адреса под приём денег, и сразу запишем туда список btc адресов.
CREATE TABLE `setup_btc` ( `idx` int(11) NOT NULL, `min` INT NOT NULL DEFAULT '0', `max` INT NOT NULL DEFAULT '0', `btc1` text, `pay_sys` tinyint(4) NOT NULL DEFAULT '1' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `setup_btc` ADD PRIMARY KEY (`idx`); INSERT INTO `setup_btc` (`idx`, `min`, `max`, `btc1`, `pay_sys`) VALUES (1, 25, 10000, '1Fzh2VcCfGYQx24gTTGoAHq91pbvnX9K8Y\n1NQez1sB55Ftgj2MHLyrU83bbpWHJ4Av7b\n1BKN7Td8e7a4wiNjMJrESDC1prCXCirvCL\n1JNTam5gE77HvxEf9jLyb6cw85GL1eKuHZ\n14j29WsyhCzAhHbTiK7z3inwacvTuuFbnz\n1GFk2tfHTdobsPhFMSStRrQhw2VXXa3dMz\n17o2JKmbrejyJdswq2T32mkK9ZpBgjo4Qw', 1);
Обратите внимание - в данном примере btc адреса вставляются через \n , т.е. через перенос строки. В вашем случае удалите указанные выше адреса (для примера вставил свои из тестового примера, смотри ниже)
Теперь основные таблицы в базе уже есть и можно перейти к собственно коду обработчика. Сам обработчик напишем на php, и после проверок повесим его на cron
Исполнение скрипта лучше всего ставить 1 раз в 1 минуту:
* * * * * /usr/bin/php /var/www/html/cron/x1.php
Этапность работы скрипта
1. Собираем заявки пользователей на платёж
2. Проверяем - есть ли на выданном адресе новый платёж, транзакция которого еще не известна базе
2.1. Если ничего нет, то пропускаем заявку
2.2. Если есть платёж в ровно требуемой сумме - запишем в базу новую транзакцию, и изменим статус платежа
2.3. Если есть платёж, но в отличающейся от рекомендованной суммы, то сделаем перерасчёт в доллары и так же запишем новую транзакцию в базу и изменим статус платежа
3. Проверим по всем ожидающим подтверждения транзакциям - есть ли подтверждения. Если есть, то зачислим деньги на баланс и поменяем статус заявки.
Код обработчика выглядит так:
<?php
// *********************************************************************************
// Для подключения к MySQL будем использовать
$host = 'localhost';
$db = 'base';
$user = 'user';
$pass = 'password';
$charset = 'utf8';
$port = '3306';
$dsn = "mysql:host=$host;port=$port;dbname=$db;charset=$charset";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $user, $pass, $opt);
// *********************************************************************************
// *********************************************************************************
// Проверим, есть ли какие новые заявки на платежи. Время на платёж - мы сделаем во фронтэнде 20 минут, а в бэкэнде поставим 30 минут. Это полезно на тот случай, если человек решит оплатить в последнюю отведённую минуту, и чтобы вручную не приходилось искать пропущенный платёж.
$list_op = array();
$a0 = 0;
$exec_v = $pdo->prepare('SELECT * FROM `pays` WHERE (`status` = 3) AND (`date_add` > DATE_SUB(NOW(), INTERVAL 30 MINUTE)) ;');
$exec_v->execute();
while ($row = $exec_v->fetch()) {
$list_op[$a0]["index"] = $row['idx'];
$list_op[$a0]["addr"] = trim($row['address']);
$list_op[$a0]["summ"] = $row['summ_btc'] * 100000000;
$list_op[$a0]["time"] = (int)$row['time_'];
$list_op[$a0]["uid"] = $row['user'];
$a0++;
}
// *********************************************************************************
// Если случился инкремент временной переменной, то значит что-то есть, что ждёт поступления
if ($a0 > 0) {
$list_hash = array();
$a0 = 0;
$exec_v = $pdo->prepare('SELECT * FROM `pays` WHERE (`status` < 3) ;');
$exec_v->execute();
while ($row = $exec_v->fetch()) {
$list_hash[$a0] = trim($row['transaction_btc']);
$a0++;
}
$body=file_get_contents('https://chain.so/api/v2/get_price/BTC/USD');
$a = json_decode($body);
$kurs = (int)$a->data->prices[0]->price;
if ($kurs < 30000) return;
if ($kurs > 80000) return;
for ($a0=0;$a0<count($list_op);$a0++){
$body="";
$c2 = 0;
if ($body=file_get_contents('https://sochain.com/api/v2/address/bitcoin/'.$list_op[$a0]["addr"])) {
$a = json_decode($body);
$c2 = count($a->data->txs);
}
if ($c2 > 6) $c2 = 6;
for ($b=0;$b<$c2;$b++){
$time_ = (int)$a->data->txs[$b]->time;
$hash_ = $a->data->txs[$b]->txid;
$cc_ = 0;
if (isset($a->data->txs[$b]->incoming)) {
$cc_ = count($a->data->txs[$b]->incoming->inputs);
}
if ($hash_ != '') {
if (in_array($hash_, $list_hash)) $cc = -1;
}
if ($list_op[$a0]["time"] <= $time_) {
for ($n=0;$n<$cc_;$n++) {
$addr_ = $a->data->address;
$summ_ = 100000000 * ($a->data->txs[$b]->incoming->value);
if ($list_op[$a0]["addr"] == $addr_) {
$x = $list_op[$a0]["summ"];
if (($x >= $summ_ - 5)&($x <= $summ_ + 5)) {
$exec_v = $pdo->prepare('UPDATE `pays` SET `status` = 2, `transaction_btc` = :hash_, `kurs` = :kurs WHERE (`idx` = :indx) ;');
$exec_v->execute(array('indx' => $list_op[$a0]["index"], 'hash_' => $hash_, 'kurs' => $kurs ));
} else {
// Событие, когда платёж пришёл немного в другом объёме, и требуется пересчитать сколько это в $
$num_pay = 0;
$exec_v = $pdo->prepare('SELECT * FROM `pays` WHERE (`transaction_btc` LIKE :hs) ;');
$exec_v->execute(array('hs' => trim($hash_)));
if ($row = $exec_v->fetch()) {
$num_pay = $row['idx'];
}
if ($num_pay == 0) {
$summ2 = (floor((($summ_ / 100000000) * $kurs) * 10)) / 10;
$summ3 = $summ_ / 100000000;
$info = 'Correct rate to: '.$kurs.' (old summ: '.($x / 100000000).')';
$exec_v = $pdo->prepare('UPDATE `pays` SET `status` = 2, `transaction_btc` = :hash_, `summ_usd` = :summ2, `summ_btc` = :summ3, `kurs` = :kurs, `text_` = :txt WHERE (`idx` = :indx) ;');
$exec_v->execute(array('indx' => $list_op[$a0]["index"], 'hash_' => $hash_, 'summ2' => $summ2, 'summ3' => $summ3, 'kurs' => $kurs, 'txt' => $info ));
}
}
}
}
}
}
}
}
// *********************************************************************************************************************
// Проверка биткоин поступлений
// Ожидание вхождения в блок, для оплаты даётся 23 часа, после чего нужно будет вручную сделать зачисление, если нет блока
$list_op = array();
$a0 = 0;
$exec_v = $pdo->prepare('SELECT * FROM `pays` WHERE (`status` = 2) AND (`date_add` > DATE_SUB(NOW(), INTERVAL 23 HOUR)) ;');
$exec_v->execute();
while ($row = $exec_v->fetch()) {
$list_op[$a0]["index"] = $row['idx'];
$list_op[$a0]["addr"] = trim($row['address']);
$list_op[$a0]["uid"] = $row['user'];
$list_op[$a0]["summ_usd"] = $row['summ_usd'];
$list_op[$a0]["tx"] = $row['transaction_btc'];
$list_op[$a0]["summ"] = $row['summ_btc'] * 100000000;
$a0++;
}
if ($list_op > 0) {
for ($a0=0;$a0<count($list_op);$a0++){
$c2 = 0;
$body="";
if ($body=file_get_contents('https://sochain.com/api/v2/address/bitcoin/'.$list_op[$a0]["addr"])) {
$a = json_decode($body);
$c2 = count($a->data->txs);
}
for ($b=0;$b<$c2;$b++){
$block = 0;
$rows_x = 0;
if (isset($a->data->txs[$b]->block_no)) {
$block = $a->data->txs[$b]->block_no;
$block = (int)$block;
}
$hash_ = $a->data->txs[$b]->txid;
if (isset($a->data->txs[$b]->incoming)) {
$rows_x = count($a->data->txs[$b]->incoming->inputs);
}
$add_money_x = 0;
for ($n=0;$n<$rows_x;$n++) {
$addr_ = "";
$summ_ = "";
$addr_ = trim($a->data->address);
$summ_ = 100000000 * ($a->data->txs[$b]->incoming->value);
if (($list_op[$a0]["addr"] == $addr_)&($list_op[$a0]["tx"] == $hash_)&($add_money_x == 0)) {
$x = $list_op[$a0]["summ"];
if (($x >= $summ_ - 500)&($x <= $summ_ + 500)) {
if ($block > 5555) {
$bal = 0;
$exec_v = $pdo->prepare('UPDATE `pays` SET `status` = 0, `date_val` = NOW() WHERE (`idx` = :indx) ;');
$exec_v->execute(array('indx' => $list_op[$a0]["index"]));
$summ_pay_z = $list_op[$a0]["summ_usd"];
$add_money_x++;
$exec_v = $pdo->prepare('UPDATE `userlist` SET `balance` = `balance` + :summ WHERE (`uid` = :uid) LIMIT 1 ;');
$exec_v->execute(array('uid' => $list_op[$a0]["uid"], 'summ' => $summ_pay_z ));
}
}
}
}
}
}
}
?>
Для теста я создал небольшой полноценный пример приёма средств.
Скачать демо версию в полном виде можете тут: Matrix File скачать скрипт
Еще одна таблица, которая используется в моём примере - это список пользователей, которым зачисляются средства.
CREATE TABLE `userlist` ( `uid` int(11) NOT NULL, `passw` varchar(50) DEFAULT NULL, `status` tinyint(4) NOT NULL DEFAULT '1', `balance` decimal(10,2) NOT NULL DEFAULT '0.00', `date_create` timestamp NULL DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `userlist` ADD PRIMARY KEY (`uid`); ALTER TABLE `userlist` MODIFY `uid` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;
Скачав демо код, вставив туда свои данные для MySQL сервера, и создав 3 таблице в базе, вы получите простое и рабочее решение по приёму средств.
МАТРИЦА (https://t.me/matrixleaks)