Простой приём средств в BTC

  • Автор темы Admin

Admin

#1
Администратор
Регистрация
31.12.2019
Сообщения
6,977
Реакции
34
Мы будем рассматривать простой вариант системы приёма платежей, где имеется определённый список 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 ));
                        }
                    }
                }
            }
        }
    }
}
?>

Для теста я создал небольшой полноценный пример приёма средств.

Тестовый вариант скрипта выложил на демо сервер: http://5.61.61.248/

Скачать демо версию в полном виде можете тут: https://send.exploit.in/download/d8416569ea4642ea/#mXDffXRR9MD246pllF4H7w

Еще одна таблица, которая используется в моём примере - это список пользователей, которым зачисляются средства.

Код:
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 таблице в базе, вы получите простое и рабочее решение по приёму средств.

Админку не выкладываю - там уже самостоятельно не сложно доделать.

Из выявленных недостатоков - приходится вручную добавлять платёж, когда в одной транзакции одновременно приходят 2 и более платежей. Это может случаться при высокой нагрузке (часто идёт монета), и монета идёт с бирж (где в 1 транзакции 100 отправителей и 100500 получателей_адресов). Можно доработать немного эту демку, и эта проблема будет решена.

Автор: vded
 

Members, viewing this thread

Сейчас на форуме нет ни одного пользователя.