| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559 |
- <?php
- namespace App\Servers;
- use App\Models\Broadcast;
- use App\Models\CoinTypes;
- use App\Models\Config;
- use App\Models\MemberCoins;
- use App\Models\Withdraw;
- use App\Servers\Eth\Utils;
- use Illuminate\Support\Facades\Log;
- use Web3p\EthereumTx\Transaction;
- /**
- * 广播接口
- */
- class BroadcastServer
- {
- public static $type_str=[
- 1=>'BTC充值',
- 2=>'ETH充值',
- 3=>'USDT充值',
- 4=>'BTC提现',
- 5=>'ETH提现',
- 6=>'USDT提现',
- 7=>'ETH手续费',
- ];
- /**
- * @param $eth_address ## 用户钱包地址
- * @return bool|mixed|string|null
- *
- * 查询用户NYTR余额
- */
- public static function getUsdtNum($eth_address)
- {
- $eth = EthereumRPCServer::getInstance();
- $tx = [];
- $tx['from'] = $eth_address; //用户地址
- // $tx['to'] = config('muc.hy_address', ''); //系统钱包地址
- $tx['to'] =Config::where('key','hy_address')->value('value'); //系统钱包地址
- $tx['data'] = Utils::decodeSolMethod('balanceOf(address)', [$eth_address]);
- $balance = $eth->call($tx);
- $balance = Utils::hex2dec($balance);
- $balance = Utils::int2fund($balance,6); // 18位小数
- $balance = Utils::fund2int($balance, 2);
- $balance = round($balance / 100, 2);
- return $balance;
- }
- /**
- * 获取ETH余额
- * @param $eth_address ##用户钱包地址
- * @return bool|mixed|string
- */
- public static function getEthNum($eth_address)
- {
- $eth = EthereumRPCServer::getInstance();
- $eth_num = $eth->getBalance($eth_address);
- $eth_num = Utils::hex2dec($eth_num);
- $eth_num = Utils::int2fund($eth_num, 18);
- return $eth_num;
- }
- /**
- * 获取BTC数量
- * @param $btc_address
- * @return string
- */
- public static function getBtcNum($btc_address)
- {
- $btc = BtcereumRPCServer::getInstance();
- $btc_num = $btc->bitcoinBalanceOfAddress($btc_address);
- return $btc_num;
- }
- public static function addBroadcast($coin_id, $money, $from, $from_key, $to, $member_id, $order_id = 0, $status_type = 0, $from_id = 0, $status = 1)
- {
- //保留数量
- $retain_num = CoinTypes::where('id', $coin_id)->value('retain_num');
- $transaction = [
- 'depend' => 0,
- 'from' => $from,
- 'to' => $to,
- 'nonce' => '',
- 'coin_id' => $coin_id,
- 'value' => '0x0',
- 'data' => !empty($tx['data']) ? $tx['data'] : Utils::fixHex(bin2hex('NYT')),
- 'chain_id' => 0,
- 'gas_price' => '',
- 'gas_limit' => '',
- 'to_address' => $to,
- 'sign' => '',
- 'hash' => $status == 5 ? '系统内部转账,直接成功,无需链上广播' : '',
- 'from_key' => $from_key,
- 'money' =>$coin_id!=4? round($money - $retain_num,6):$money,
- 'status' => $status,
- 'type' => $status_type,
- 'm_id' => $member_id,
- 'order_id' => $order_id,
- // 'from_id' => $from_id,
- 'retain_num' => $retain_num,
- 'send_money' => $money,
- ];
- if ($coin_id == 1) {
- // $btc = BtcereumRPCServer::getInstance();
- // $feeAddressUXTO = $btc->listunspent(0, 999999, [$from]);
- // if (empty($feeAddressUXTO)) {
- // $transaction['error'] = "手续费地址uxto为空";
- // $transaction['status'] = 4;
- // } else {
- // $inputs = [];
- // foreach ($feeAddressUXTO as $item) {
- // $inputs[] = [
- // 'txid' => $item['txid'],
- // 'vout' => $item['vout'],
- // ];
- // }
- // $output = [$to => $transaction['money']];
- // $rawtx = $btc->createrawtransaction($inputs, $output);
- // if ($rawtx === false) {
- // $transaction['error'] = "创建裸交易失败";
- // $transaction['status'] = 4;
- // } else {
- // $transaction['data'] = $rawtx;
- // }
- // }
- } else {
- $eth = EthereumRPCServer::getInstance();
- $transaction['chain_id'] = $eth->chainId;
- $depend = 0;
- if ($coin_id == 4) {
- $hy_address=Config::where('key','hy_address')->value('value');
- $tx = static::build(
- $from,
- $hy_address,//系统钱包地址
- '0x0',
- Utils::decodeSolMethod(
- 'transfer(address,uint256)',
- [$to, Utils::fund2int($money, 6)]
- // [$to, Utils::fund2int($money, 18)]
- )
- );
- $transaction['from'] = $tx['from'];
- $transaction['to'] = $tx['to'];
- $transaction['data'] = $tx['data'];
- $my_eth = static::getEthNum($tx['from']);
- if ($my_eth * 1 < 0.002) {
- $depend = static::withholdServiceCharge($tx, $member_id);
- }
- }else{
- $transaction['value'] =Utils::dec2hex(Utils::fund2int($transaction['money'] * 1)); // 转账金额
- $transaction['data'] = '0x0';
- }
- $transaction['depend'] = $depend;
- // $nonce = $eth->getTransactionCount($transaction['from']);
- // $transaction['nonce'] = $nonce;//交易顺序十六进制。由eth_getTransactionCount获取
- // $gas_price = $eth->getGasPrice();
- // $transaction['gas_price'] = Utils::dec2hex(Utils::toWei("1gwei") + Utils::hex2dec($gas_price));//燃料十六进制。由eth_estimateGas获取
- // $gas_limit = static::getGasLimit($transaction);
- // $transaction['gas_limit'] = $gas_limit;
- //写入数据库代码 $transaction
- }
- $transaction = Broadcast::create($transaction);
- // //写入 返回成功
- return $transaction->{'id'};
- }
- /**
- * 导入广播
- * @param $from
- * @param $to
- * @param $nonce
- * @param $value
- * @param $data
- * @param $chain_id
- * @param $gas_price
- * @param $gas_limit
- * @param $sign
- * @param $hash
- * @param $money
- * @param $order_id
- * @param $coin_id
- * @param $status
- * @return mixed
- */
- public static function addSysBroadcast($from, $to, $nonce, $value, $data, $chain_id, $gas_price, $gas_limit, $sign, $hash, $money, $order_id, $coin_id, $status)
- {
- $withdraws = Withdraw::where('id', $order_id)->first();
- if (empty($withdraws)) {
- Log::info('导入提现信息不存在,提现ID:' . $order_id);
- return false;
- }
- if($withdraws->{'status'}!=1)return false;
- $transaction_id = Broadcast::where('order_id', $order_id)->where('type', '2')->value('id');
- //保留数量
- $transaction = [
- 'depend' => 0,
- 'from' => $from,
- 'to' => $to,
- 'nonce' => $nonce,
- 'coin_id' => $coin_id,
- 'value' => $value,
- 'data' => $data,
- 'chain_id' => $chain_id,
- 'gas_price' => $gas_price,
- 'gas_limit' => $gas_limit,
- 'sign' => $sign,
- 'hash' => $hash,
- 'from_key' => '',
- 'money' => $money,
- 'status' => 3,
- 'type' => $status,
- 'm_id' => $withdraws->{'m_id'},
- 'order_id' => $order_id,
- 'created_at' => date('Y-m-d H:i:s'),
- 'updated_at' => date('Y-m-d H:i:s'),
- ];
- if (empty($transaction_id)) {
- $transaction_id = Broadcast::insertGetId($transaction);
- } else {
- Broadcast::where('id', $transaction_id)->update($transaction);
- }
- Withdraw::where('id', $order_id)->update(['updated_at' => date('Y-m-d H:i:s'),'hash'=>$hash, 'status' => '2']);
- // //写入 返回成功
- return $transaction_id;
- }
- /**
- * 广播签名
- * @return bool
- */
- public static function signBroadcast()
- {
- $btc = BtcereumRPCServer::getInstance();
- $list = Broadcast::where('status', '1')->select(['id', 'depend', 'chain_id', 'm_id', 'from', 'to', 'nonce', 'value', 'data', 'gas_price', 'gas_limit', 'sign', 'money', 'from_key', 'coin_id'])->groupBy('m_id')->limit(10)->get()->toArray();
- // $service_money='4000000000000000';
- // 手续费交易 转账0.0015个
- // $serviceFee = Utils::dec2hex($service_money); // 手续费
-
- if (empty($list)) return false;
- $sys_wei=Config::where('key','service_charge')->value('value');
- $sys_wei=empty($sys_wei)?'15':$sys_wei;
- $eth = EthereumRPCServer::getInstance();
- foreach ($list as $value) {
- $update_info = [];
- $from_key = PassServer::getSecretKey($value['from_key'], $value['m_id']);
- $send_num = Broadcast::whereIn('status', ['2'])->where('from', $value['from'])->count();
- if ($send_num > 0) continue;
- if ($value['depend']) {
- $num = Broadcast::where('id', $value['depend'])->where('status', 5)->where('updated_at','<',date('Y-m-d H:i:s',time()-15))->count();
- if ($num <= 0) continue;
- }
- if ($value['coin_id'] == 1) {
- $feeAddressUXTO = $btc->listunspent(0, 999999, [$value['from']]);
- if (empty($feeAddressUXTO)) {
- $update_info['error'] = "手续费地址uxto为空";
- $update_info['status'] = 4;
- } else {
- $inputs = [];
- foreach ($feeAddressUXTO as $item) {
- $inputs[] = [
- 'txid' => $item['txid'],
- 'vout' => $item['vout'],
- ];
- }
- $output = [$value['to'] => $value['money']*1];
- $rawtx = $btc->createrawtransaction($inputs, $output);
- if ($rawtx === false) {
- $update_info['error'] = "创建裸交易失败";
- $update_info['status'] = 4;
- } else {
- $value['data'] = $rawtx;
- $privKeys[] = $from_key;
- $sign = $btc->signrawtransactionwithkey($value['data'], $privKeys,null);
- if ($sign === false) {
- $update_info['error'] = '签名失败';
- $update_info['status'] = 5;
- } else {
- $update_info['sign'] = $sign['hex'];
- $update_info['status'] = 2;
- }
- }
- }
- } else {
-
- if($value['coin_id']==4){
- $my_eth = static::getEthNum($value['from']);
- //dd( $my_eth);
- if ($my_eth * 1 < 0.005) {
- $depend = static::withholdServiceCharge($value, $value['m_id']);
- Broadcast::where('id', $value['id'])->update(['depend' => $depend]);
- continue;
- }
- }else{
- // $value['value'] =Utils::dec2hex(Utils::fund2int($value['money'] * 1)); // 转账金额
- }
- if(empty($value['nonce']) || true){
- $nonce = $eth->getTransactionCount($value['from']);
- //交易顺序十六进制。由eth_getTransactionCount获取
- $nonce_count = Broadcast::where('nonce', $nonce)->where('from',$value['from'])->where('id','<>', $value['id'])->count();
- if ($nonce_count >= 1) {
- continue;
- // $nonce=Utils::dec2hex(Utils::hex2dec($nonce) + 1);
- }
- $value['nonce'] = $nonce;
- }
- $gas_price = $eth->getGasPrice();
-
- $value['gas_price'] = Utils::dec2hex(Utils::toWei($sys_wei."gwei") + Utils::hex2dec($gas_price));//燃料十六进制。由eth_estimateGas获取
- // $value['gas_price'] = $gas_price;//燃料十六进制。由eth_estimateGas获取
- $gas_limit = static::getGasLimit($value);
- $value['gas_limit'] = $gas_limit;
- $sign = static::sign($value, $from_key); //交易签名
-
- if ($sign === false) {
- $update_info['error'] = '签名失败';
- $update_info['status'] = 4;
- } else {
- $update_info['sign'] = $sign;
- $update_info['status'] = 2;
- $update_info['nonce'] = $value['nonce'];
- $update_info['gas_limit'] = $value['gas_limit'];
- $update_info['gas_price'] = $value['gas_price'];
- }
- }
- Broadcast::where('id', $value['id'])->update($update_info);
- sleep(5);
- }
- return true;
- }
- /**
- * 广播交易
- * @return bool
- */
- public static function sendBroadcast()
- {
- $btc = BtcereumRPCServer::getInstance();
- $eth = EthereumRPCServer::getInstance();
- $list = Broadcast::where('status', '2')->select(['id', 'm_id', 'from', 'to', 'nonce', 'value', 'data', 'gas_price', 'gas_limit', 'sign', 'money', 'from_key', 'coin_id'])->limit(10)->get()->toArray();
- if (empty($list)) return false;
- foreach ($list as $value) {
- $update_info = [];
- if ($value['coin_id'] == 1) {
- $txid = $btc->sendrawtransaction($value['sign']);
- if ($txid == false) {
- $update_info['error'] = '广播失败';
- $update_info['status'] = 4;
- } else {
- $update_info['hash'] = $txid;
- $update_info['status'] = 3;
- }
- } else {
- $hash = $eth->sendRawTransaction($value['sign'], $error);//广播交易
- if ($hash == false) {
- $update_info['error'] = json_encode($error);
- $update_info['status'] = 4;
- } else {
- $update_info['hash'] = $hash;
- $update_info['status'] = 3;
- }
- }
- Broadcast::where('id', $value['id'])->update($update_info);
- }
- return true;
- }
- /**
- * 广播查询
- */
- public static function getBroadcast(){
- $btc = BtcereumRPCServer::getInstance();
- $eth = EthereumRPCServer::getInstance();
- $list = Broadcast::where('status', '3')->select(['id', 'm_id', 'from', 'to', 'send_money', 'value', 'coin_id', 'type', 'sign', 'money', 'from_key', 'coin_id','hash','send_money','order_id'])->limit(10)->get()->toArray();
- if (empty($list)) return false;
- foreach ($list as $value) {
- $update_info = [];
- if ($value['coin_id'] == 1) {
- $deal_info=$btc->getrawtransaction ($value['hash'],true);
- if(empty($deal_info['confirmations']) || $deal_info['confirmations'] <=3){
- continue;
- }else{
- $update_info['success'] = json_encode($deal_info);
- $update_info['status'] = 5;
- }
- } else {
- $receipt = $eth->getTransactionReceipt($value['hash']);//交易查询
- if (empty($receipt)) {
- //交易正在广播中,下次继续查询
- continue;
- } else {
- //交易已完成 返回数据格式数据 ,将数据json保存
- if ($receipt['status'] != '0x1') {
- $update_info['error'] = json_encode($receipt);
- $update_info['status'] = 4;
- }else{
- $update_info['success'] = json_encode($receipt);
- $update_info['status'] = 5;
- }
- }
- }
- if(!empty($update_info)){
- Broadcast::where('id', $value['id'])->update($update_info);
- if($update_info['status']==5){
- //广播成功,增加会员余额
- if($value['type']<=3){
- $member_coin= MemberCoins::where('m_id',$value['m_id'])->where('coin_id',$value['coin_id'])->select(['id','coin_name','coin_id','num','m_id'])->first();
- MemberCoins::where('id',$member_coin->{'id'})->update(['num'=>$member_coin->{'num'}+$value['send_money']]);
- MoneyDetailServer::write($member_coin['coin_id'], MoneyDetailServer::$status['coin_recharge'], $value['send_money'], MoneyDetailServer::$add_reduce['add'], $member_coin->{'m_id'}, $member_coin->{'mobile'}, '充币' .$value['send_money'] .''. $member_coin->{'coin_name'}, '', $value['id'], $member_coin->{'num'}, 'Recharge ' . $member_coin->{'money'} . $member_coin->{'coin_name'});
- }elseif($value['type']<=6){
- $withdraws = Withdraw::where('id', $value['order_id'])->where('m_id', $value['m_id'])->first();
- if (!empty($withdraws)) {
- Withdraw::where('id', $value['order_id'])->update([ 'status' => '3']);
- $member_coin = MemberCoins::where('m_id', $value['m_id'])->where('coin_id', $value['coin_id'])->select(['id', 'coin_name', 'coin_id', 'num', 'm_id','lock_num'])->first();
- $lock_num = $member_coin->{'lock_num'} - $withdraws->{'money'};
- if ($lock_num < 0) $lock_num = 0;
- MemberCoins::where('id', $member_coin->{'id'})->update(['lock_num' => $lock_num]);
- }
- }
- }
- }
- }
- return true;
- }
- /**
- * 系统手续费转账
- * @param $tx
- * @param $member_id
- * @return mixed
- */
- public static function withholdServiceCharge($tx, $member_id)
- {
- $eth = EthereumRPCServer::getInstance();
- $gasPrice = $eth->getGasPrice(); // 手续费
- $cb_address = Config::where('key', 'cb_address')->value('value');
- $address_key = Config::where('key', 'address_key')->value('value');
- $sys_wei=Config::where('key','service_charge')->value('value');
- $service_money=Config::where('key','service_money')->value('value');
- $sys_wei=empty($sys_wei)?'15':$sys_wei;
- $service_money=empty($service_money)?'3000000000000000':$service_money;
- $tx = [
- 'from' => $cb_address,
- 'to' => $tx['from'],
- 'value' => '0x0',
- 'data' => $tx['data'],
- ];
- $gasLimit = $eth->estimateGas($tx);
- // 手续费交易 转账0.0015个
- $serviceFee = Utils::dec2hex($service_money); // 手续费
- // 广播手续费
- $transaction = [
- 'depend' => 0,
- 'from' => $cb_address,
- 'to' => $tx['to'],
- 'nonce' => '',
- 'value' => $serviceFee,//转账0.004个
- 'data' => '0x0',
- 'money' => round($service_money/1000000000000000000,6),
- 'gas_limit' => $gasLimit,
- 'chain_id' => $eth->chainId,
- 'gas_price' => '',
- 'to_address' => $tx['to'],
- 'coin_id' => 2,
- 'sign' => '',
- 'hash' => '',
- 'from_key' => $address_key,//系统支付秘钥
- 'status' => 1,//系统支付秘钥
- 'type' => 7,//系统支付秘钥
- 'm_id' => 0,
- 'send_money' => round($service_money/1000000000000000000,6),
- ];
- $nonce = $eth->getTransactionCount($transaction['from']);
- $transaction['nonce'] = $nonce;//交易顺序十六进制。由eth_getTransactionCount获取
- $transaction['gas_price'] = Utils::dec2hex(Utils::toWei($sys_wei."gwei") + Utils::hex2dec($gasPrice));//燃料十六进制。由eth_estimateGas获取
- $transaction['gas_limit'] = $gasLimit;
- //写入数据库代码 $transaction
- $nytr = Broadcast::create($transaction);
- return $nytr->{'id'};
- }
- /**
- * 转账内容拼接
- * @param $from
- * @param $to
- * @param $value
- * @param $data
- * @return array
- * @throws
- */
- protected static function build($from, $to, $value, $data)
- {
- $tx = [];
- $tx['from'] = $from;
- $tx['to'] = $to;
- $tx['value'] = $value;
- $tx['data'] = $data;
- return $tx;
- }
- /**
- * @param $transaction
- * @return string
- */
- public static function getGasLimit($transaction)
- {
- $tx = [
- 'from' => $transaction['from'],
- 'to' => $transaction['to'],
- 'nonce' => $transaction['nonce'],
- 'value' => $transaction['value'],
- 'data' => $transaction['data'],
- 'chainId' => 1,
- 'gasPrice' => $transaction['gas_price'],
- ];
- $eth = EthereumRPCServer::getInstance();
- $gasLimit = $eth->estimateGas($tx);
- if (!$gasLimit) {
- $gasLimit = 10 * 10000; // 预估失败, 最高10万
- }
- return $gasLimit;
- }
- protected static function sign($transaction, $key)
- {
- $tx = [
- 'from' => $transaction['from'],
- 'to' => $transaction['to'],
- 'nonce' => $transaction['nonce'],
- 'value' => $transaction['value'],
- 'data' => $transaction['data'],
- 'chainId' => $transaction['chain_id'],
- 'gasPrice' => $transaction['gas_price'],
- 'gasLimit' => $transaction['gas_limit'],
- ];
- // 数据签名
- $tr = new Transaction($tx);
- $tr->sign($key);
- return Utils::fixHex($tr->serialize()->toString('hex'));
- }
- }
|