wallet tron transactions

This commit is contained in:
cano
2024-03-25 06:15:36 +08:00
parent 4b8f205e86
commit 489090382f
83 changed files with 5424 additions and 1343 deletions

View File

@ -0,0 +1,228 @@
<?php
namespace App\Service\Coin\Tron;
use App\Bean\Model\Wallet\Wallet\WalletAddressTransactionBean;
use App\Bean\Queue\Wallet\QueueEventBean;
use App\Bean\Queue\Wallet\QueueWalletBlockBean;
use App\Bean\Queue\Wallet\QueueWalletBlockTransactionBean;
use App\Bean\Queue\Wallet\QueueWalletPlatformTransactionBean;
use App\Bean\Sdk\Wallet\Tron\EventBean;
use App\Cache\Key\TronKeyCache;
use App\Cache\Set\TronWalletAddressSetCache;
use App\Exceptions\QueueException;
use App\Jobs\Wallet\WalletAddressTransactionQueue;
use App\Jobs\Wallet\WalletBlockQueue;
use App\Jobs\Wallet\WalletBlockTransactionQueue;
use App\Jobs\Wallet\WalletPlatformTransactionQueue;
use App\Models\Wallet\Tron\WalletTronBlockModel;
use App\Models\Wallet\Wallet\WalletAddressModel;
use App\Models\Wallet\Wallet\WalletAddressTransactionModel;
use App\Models\Wallet\Wallet\WalletCurrencyModel;
use App\Tools\Logs;
use Sdk\Wallet\UsdtTrc20;
class UsdtTrx20Service
{
protected UsdtTrc20 $usdtTrc20Sdk;
function __construct()
{
$this->usdtTrc20Sdk = new UsdtTrc20();
}
function getHandle(): \Sdk\Wallet\Trc20Sdk
{
return $this->usdtTrc20Sdk->getHandler();
}
//定时请求当前区块比对redis中当前区块差值存入队列
function checkNowBlock(): void
{
$oNowBlockBean = $this->getHandle()->getNowBlockNumber();
//查询redis中当前区块
$oTronKeyCache = new TronKeyCache();
$sLocalNowBlock = $oTronKeyCache->getNowBlock();
if (empty($sLocalNowBlock)) { //不存在就从数据库中取
$oWalletTronBlockModel = new WalletTronBlockModel();
$sLocalNowBlock = $oWalletTronBlockModel->getLastBlockNumber();
if (!empty($sLocalNowBlock)) $oTronKeyCache->setNowBlock($sLocalNowBlock);
}
$oWalletTronBlockModel = new WalletTronBlockModel();
//如果都不存在,就直接投递到队列
if (empty($sLocalNowBlock)) {
$res = $oWalletTronBlockModel->insertByBlockNum($oNowBlockBean->getBlockNumber());
if (!$res) return;
$oQueueWalletBlockBean = new QueueWalletBlockBean();
$oQueueWalletBlockBean->setId($res->id);
$oQueueWalletBlockBean->setBlockNumber($oNowBlockBean->getBlockNumber());
WalletBlockQueue::putToQueue($oQueueWalletBlockBean);
return;
}
//如果相等获取大于,就不处理
if ($sLocalNowBlock >= $oNowBlockBean->getBlockNumber()) {
return;
}
//如果不相等,获取差值一个个投递到队列
for ($i = $sLocalNowBlock + 1; $i <= $oNowBlockBean->getBlockNumber(); $i++) {
$res = $oWalletTronBlockModel->insertByBlockNum($i);
if (!$res) continue;
$oQueueWalletBlockBean = new QueueWalletBlockBean();
$oQueueWalletBlockBean->setId($res->id);
$oQueueWalletBlockBean->setBlockNumber($i);
WalletBlockQueue::putToQueue($oQueueWalletBlockBean);
}
}
//监听处理区块
public function tronBlockConsumer(QueueWalletBlockBean $oQueueWalletBlockBean): void
{
$oWalletTronBlockModel = new WalletTronBlockModel();
$oResModel = $oWalletTronBlockModel->findItem($oQueueWalletBlockBean->getId());
if (!$oResModel) throw new QueueException('区块不存在');
if ($oResModel->status != WalletTronBlockModel::STATUS_WAIT) return;
$oResModel->status = WalletTronBlockModel::STATUS_PROCESS;
$oResModel->save();
$blockNumber = $oQueueWalletBlockBean->getBlockNumber();
$fingerprint = null;
try {
//循环获取区块所有转账信息
while (true) {
$oResponseBean = $this->getHandle()->getTrc20BlockEventsTransferByBlockNumber($blockNumber, $fingerprint);
if ($oResponseBean === false) throw new QueueException('获取区块信息失败');
if (empty($oResponseBean)) break;
if ($oResponseBean->getSuccess() === false) break;
$fingerprint = $oResponseBean->getMeta()->getFingerprint();
if (empty($oResponseBean->getData())) break;
//投递到区块账变队列
$oQueueWalletBlockTransactionBean = new QueueWalletBlockTransactionBean();
$oQueueWalletBlockTransactionBean->setData($oResponseBean->getData());
WalletBlockTransactionQueue::putToQueue($oQueueWalletBlockTransactionBean);
if (empty($fingerprint)) break;
}
$updateItem = [
'id' => $oResModel->id,
'status' => WalletTronBlockModel::STATUS_FINISH,
];
$oWalletTronBlockModel->updateItem($updateItem);
} catch (\Exception $e) {
Logs::ErrLog(__FUNCTION__, $e, $oQueueWalletBlockBean->toArray());
$oQueueWalletBlockBean->IncrTryTimes();
if (!$oQueueWalletBlockBean->checkTryTimes()) { //超出重试次数
$updateItem = [
'id' => $oResModel->id,
'status' => WalletTronBlockModel::STATUS_FAIL,
];
$oWalletTronBlockModel->updateItem($updateItem);
return;
}
WalletBlockQueue::putToQueue($oQueueWalletBlockBean, 30);
}
}
//监听处理区块每笔合约交易
public function tronBlockTransactionConsumer(QueueWalletBlockTransactionBean $oQueueWalletBlockTransactionBean): void
{
$aBlockEvents = $oQueueWalletBlockTransactionBean->getData();
foreach ($aBlockEvents as $item) {
$oEventBean = new EventBean($item);
try {
$this->tronBlockTransaction($oEventBean);
} catch (\Exception $e) {
Logs::ErrLog(__FUNCTION__, $e, $oEventBean->toArray());
}
}
}
//监听处理单个合约交易
function tronBlockTransaction(EventBean $oEventBean): void
{
//检查合约
if ($oEventBean->getContractAddress() != UsdtTrc20::CONTRACT_ADDRESS) return;
$from_addr = $oEventBean->getResult()->getFrom();
$to_addr = $oEventBean->getResult()->getTo();
$value = $oEventBean->getResult()->getValue();
//检查交易双方是否是平台地址
$oTronWalletAddressSetCache = new TronWalletAddressSetCache();
$is_from = $oTronWalletAddressSetCache->checkKey($from_addr);
$is_to = $oTronWalletAddressSetCache->checkKey($to_addr);
if (!$is_from && !$is_to) return;
//投递到钱包地址账变处理队列
$oQueueEventBean = new QueueEventBean($oEventBean->toArray());
WalletAddressTransactionQueue::putToQueue($oQueueEventBean);
return;
}
//用户钱包地址交易账变处理
function walletAddressTransactionConsumer(QueueEventBean $bean): void
{
try {
$from_addr = $bean->getResult()->getFrom();
$to_addr = $bean->getResult()->getTo();
$value = $bean->getResult()->getValue();
//查询地址是否存在
$oWalletAddressModel = new WalletAddressModel();
$resFromModel = $oWalletAddressModel->findByAddressHex($from_addr, WalletCurrencyModel::CODE_USDT_TRC20);
$resToModel = $oWalletAddressModel->findByAddressHex($to_addr, WalletCurrencyModel::CODE_USDT_TRC20);
if (!$resFromModel && !$resToModel) return;
//先落地到数据库
$oWalletAddressTransactionModel = new WalletAddressTransactionModel();
$oWalletAddressTransactionBean = new WalletAddressTransactionBean();
$oWalletAddressTransactionBean->setCurrencyCode(WalletCurrencyModel::CODE_USDT_TRC20);
$oWalletAddressTransactionBean->setBlockTransactionId($bean->getTransactionId());
$oWalletAddressTransactionBean->setBlockNumber($bean->getBlockNumber());
$oWalletAddressTransactionBean->setBlockEventName($bean->getEventName());
$oWalletAddressTransactionBean->setBlockFromAddress($bean->getResult()->getFrom());
$oWalletAddressTransactionBean->setBlockToAddress($bean->getResult()->getTo());
$oWalletAddressTransactionBean->setBlockValue($bean->getResult()->getValue());
$oWalletAddressTransactionBean->setIsNotify(WalletAddressTransactionModel::IS_NOTIFY_WAIT);
if ($resToModel) { //充值
$oWalletAddressTransactionBean->setType(WalletAddressTransactionModel::TYPE_RECHARGE);
$oWalletAddressTransactionBean->setWalletAddressId($resToModel->id);
$resRecharge = $oWalletAddressTransactionModel->typeRecharge($oWalletAddressTransactionBean);
if (!$resRecharge) throw new QueueException('WalletAddressTransactionModel addTransaction recharge error');
//投递到处理平台用户账变队列
$this->addToQueue($oWalletAddressTransactionBean);
}
if ($resFromModel) { //提现
$oWalletAddressTransactionBean->setType(WalletAddressTransactionModel::TYPE_WITHDRAW);
$oWalletAddressTransactionBean->setWalletAddressId($resFromModel->id);
$resWithdraw = $oWalletAddressTransactionModel->typeWithdraw($oWalletAddressTransactionBean);
if (!$resWithdraw) throw new QueueException('WalletAddressTransactionModel addTransaction withdraw error');
//投递到处理平台用户账变队列
$this->addToQueue($oWalletAddressTransactionBean);
}
} catch (\Exception $e) {
Logs::ErrLog(__FUNCTION__, $e, $bean->toArrayNotNull());
$bean->IncrTryTimes();
if($bean->checkTryTimes()) return;
WalletAddressTransactionQueue::putToQueue($bean, 30);
}
}
function addToQueue(WalletAddressTransactionBean $bean): void
{
$oQueueWalletPlatformTransactionBean = new QueueWalletPlatformTransactionBean();
$oQueueWalletPlatformTransactionBean->setWalletId($bean->getWalletAddressId());
$oQueueWalletPlatformTransactionBean->setWalletTransactionId($bean->getId());
$oQueueWalletPlatformTransactionBean->setBlockTransactionId($bean->getBlockTransactionId());
$oQueueWalletPlatformTransactionBean->setAmount($bean->getAmount());
$oQueueWalletPlatformTransactionBean->setType($bean->getType());
WalletPlatformTransactionQueue::putToQueue($oQueueWalletPlatformTransactionBean);
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Service;
use App\Bean\Queue\Wallet\QueueWalletPlatformTransactionBean;
use App\Exceptions\QueueException;
use App\Models\Wallet\Platform\WalletPlatformBalanceTransactionModel;
use App\Models\Wallet\Platform\WalletPlatformBindModel;
class PlatformRechargeService
{
function walletPlatformTransactionConsumer(QueueWalletPlatformTransactionBean $bean): void
{
//根据钱包id查找平台和用户
$oWalletPlatformBindModel = new WalletPlatformBindModel();
$resBindModel = $oWalletPlatformBindModel->findItem($bean->getWalletId());
if (!$resBindModel) throw new QueueException('钱包不存在');
$oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel();
$res = $oWalletPlatformBalanceTransactionModel->typeRecharge(
$resBindModel->platform_id,
$resBindModel->uid,
$resBindModel->currency_code,
$bean->getAmount(),
$bean->getWalletId(),
$bean->getBlockTransactionId(),
$bean->getWalletTransactionId()
);
if (!$res) throw new QueueException('typeRecharge fail');
}
}

View File

@ -0,0 +1,130 @@
<?php
namespace App\Service;
use App\Bean\Queue\Wallet\QueueWalletPlatformTransactionBean;
use App\Bean\Queue\Wallet\QueueWalletPlatformWithdrawTransferBean;
use App\Exceptions\QueueException;
use App\Models\Wallet\Platform\WalletPlatformBalanceTransactionModel;
use App\Models\Wallet\Platform\WalletPlatformBindModel;
use App\Models\Wallet\Wallet\WalletAddressModel;
use App\Models\Wallet\Wallet\WalletCurrencyModel;
use App\Tools\Logs;
use App\Tools\Times;
use Illuminate\Support\Facades\DB;
use Sdk\Wallet\TokenAddress;
use Sdk\Wallet\UsdtTrc20;
class PlatformWithdrawService
{
function withdrawTransferConsumer(QueueWalletPlatformWithdrawTransferBean $bean): void
{
//获取账变
$oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel();
$resModel = $oWalletPlatformBalanceTransactionModel->findItem($bean->getTransactionId());
if (!$resModel) throw new QueueException('账变不存在');
if($resModel->status != WalletPlatformBalanceTransactionModel::STATUS_WAIT) throw new QueueException('账变状态不正确');
//更新账变状态
$updateItem = [
'id' => $bean->getTransactionId(),
'status' => WalletPlatformBalanceTransactionModel::STATUS_PROCESSING,
'updated_at' => Times::getNowDateTime(),
];
$res = $oWalletPlatformBalanceTransactionModel->updateItem($updateItem);
if (!$res) throw new QueueException('更新账变状态失败');
$currency_code = $resModel->currency_code;
//提现
try {
//根据币种调用不同的提现方法
switch ($currency_code) {
case WalletCurrencyModel::CODE_USDT_TRC20: //提现USDT
$txId = $this->withdrawUsdtTrc20($resModel);
break;
default:
throw new QueueException('不支持的币种');
}
Logs::SuccLog(__FUNCTION__, $bean->toArrayNotNull());
}catch (\Exception $e){
//更新账变状态
$updateItem = [
'id' => $bean->getTransactionId(),
'status' => WalletPlatformBalanceTransactionModel::STATUS_FAIL,
'updated_at' => Times::getNowDateTime(),
];
$oWalletPlatformBalanceTransactionModel->updateItem($updateItem);
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, $bean->toArrayNotNull());
throw new QueueException($e->getMessage());
}
}
function withdrawUsdtTrc20($model): string
{
try {
DB::beginTransaction();
$oWalletAddressModel = new WalletAddressModel();
//获取出金地址
$resFromModel = $oWalletAddressModel->findWithdrawWallet($model->currency_code, $model->amount);
if(!$resFromModel) throw new QueueException('提现地址不足');
$from_wallet_address_id = $resFromModel->id;
$from_wallet_address = $resFromModel->address_base58;
//获取入金地址
$to_wallet_address = $model->to_wallet_address;
if(!empty($to_wallet_address)) throw new QueueException('平台钱包id错误');
$fromAddress = new TokenAddress($resFromModel->address_base58, $oWalletAddressModel->decodePrivateKey($resFromModel->private_key));
$toAddress = new TokenAddress($to_wallet_address);
$amount = abs($model->amount);
//调用sdk发起提现
$sdk = new UsdtTrc20();
$oTransferTransactionBean = $sdk->getHandler()->trc20Transfer($fromAddress,$toAddress, $amount);
if(!$oTransferTransactionBean) throw new QueueException('提现sdk发起失败');
if(empty($oTransferTransactionBean->getTxID())) throw new QueueException('提现sdk发起失败');
//存储交易id
$updateItem = [
'id' => $model->id,
'block_transaction_id' => $oTransferTransactionBean->getTxID(),
'from_wallet_address_id' => $from_wallet_address_id,
'from_wallet_address' => $from_wallet_address,
'updated_at' => Times::getNowDateTime(),
];
$oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel();
$res = $oWalletPlatformBalanceTransactionModel->updateItem($updateItem);
if(!$res) throw new QueueException('更新账变失败');
DB::commit();
return $oTransferTransactionBean->getTxID();
}catch (\Exception $e){
DB::rollBack();
throw new QueueException($e->getMessage());
}
}
function walletPlatformTransactionConsumer(QueueWalletPlatformTransactionBean $bean): void
{
//根据txid查找平台和用户
$oWalletPlatformBindModel = new WalletPlatformBindModel();
$resBindModel = $oWalletPlatformBindModel->findItem($bean->getWalletId());
if (!$resBindModel) throw new QueueException('钱包不存在');
$oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel();
$resModel = $oWalletPlatformBalanceTransactionModel->findByBlockTransactionId($bean->getBlockTransactionId(), WalletPlatformBalanceTransactionModel::TYPE_WITHDRAW_DEC);
if (!$resModel) throw new QueueException('账变不存在');
if($resModel->status != WalletPlatformBalanceTransactionModel::STATUS_PROCESSING) throw new QueueException('账变状态不正确');
$res = $oWalletPlatformBalanceTransactionModel->typeWithdrawSecondCallback(
$resModel->id,
WalletPlatformBalanceTransactionModel::STATUS_SUCCESS,
null,
$bean->getWalletTransactionId(),
);
if (!$res) throw new QueueException('typeWithdrawSecondCallback fail');
}
}