BroadcastServer.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. <?php
  2. namespace App\Servers;
  3. use App\Models\Broadcast;
  4. use App\Models\ContractDistribution;
  5. use App\Servers\Icon\BanRPC;
  6. use App\Servers\Icon\Utils;
  7. use Web3p\EthereumTx\Transaction;
  8. /**
  9. * 广播接口
  10. */
  11. class BroadcastServer
  12. {
  13. public static $type_str=[
  14. ];
  15. static private $server = null;
  16. /**
  17. * 创建对象
  18. * @return BroadcastServer
  19. */
  20. static function creatServer()
  21. {
  22. if (empty(self::$server)) self::$server = new BroadcastServer();
  23. return self::$server;
  24. }
  25. /**
  26. * 创建广播信息
  27. * @param $coin_id
  28. * @param $money
  29. * @param $from
  30. * @param $from_key
  31. * @param $to
  32. * @param $member_id
  33. * @param int $order_id
  34. * @param int $status_type
  35. * @param int $status
  36. * @return mixed
  37. */
  38. public static function addBroadcast($coin_id, $money, $from, $from_key, $to, $member_id, $order_id = 0, $status_type = 0, $status = 1)
  39. {
  40. //保留数量
  41. $transaction = [
  42. 'depend' => 0,
  43. 'from' => $from,
  44. 'to' => $to,
  45. 'nonce' => '',
  46. 'coin_id' => $coin_id,
  47. 'value' => '0x0',
  48. 'data' => !empty($tx['data']) ? $tx['data'] : Utils::fixHex(bin2hex('NYT')),
  49. 'chain_id' => 0,
  50. 'gas_price' => '',
  51. 'gas_limit' => '',
  52. 'to_address' => $to,
  53. 'sign' => '',
  54. 'success' => '',
  55. 'hash' => $status == 5 ? '系统内部转账,直接成功,无需链上广播' : '',
  56. 'from_key' => $from_key,
  57. 'money' =>round($money,6),
  58. 'status' => $status,
  59. 'type' => $status_type,
  60. 'm_id' => $member_id,
  61. 'order_id' => $order_id,
  62. ];
  63. $transaction = Broadcast::create($transaction);
  64. return $transaction->{'id'};
  65. }
  66. /**
  67. * 广播查询
  68. */
  69. public function getBroadcast()
  70. {
  71. $list = Broadcast::where('status', '2')->select(['id', 'm_id', 'from', 'to', 'value', 'coin_id', 'type', 'sign', 'money', 'from_key', 'coin_id', 'hash', 'order_id'])->limit(100)->get();
  72. $ret_type=false;
  73. if (empty($list)) return $ret_type;
  74. $bnbServer=BanRPC::creatServer();
  75. foreach ($list as $value) {
  76. $receipt = $bnbServer->getTransactionReceipt($value['hash']);//交易查询
  77. if (empty($receipt)) {
  78. //交易正在广播中,下次继续查询
  79. continue;
  80. } else {
  81. //交易已完成 返回数据格式数据 ,将数据json保存
  82. $distribution=ContractDistribution::where('id',$value->{'order_id'})->where('type',$value->{'type'})->first();
  83. if ($receipt['status'] != '0x1') {
  84. $update_info['error'] = '广播提交失败';
  85. $update_info['status'] = 3;
  86. $distribution->update(['status' => 2]);
  87. } else {
  88. $update_info['status'] = 4;
  89. $update_info['end_time'] = time();
  90. $distribution->update(['status' => 3]);
  91. }
  92. $value->update($update_info);
  93. }
  94. }
  95. return $list->count();
  96. }
  97. /**
  98. * 交易广播
  99. */
  100. function sendBroadcast(){
  101. $list = Broadcast::where('status', '1')->where([['end_time','=',0,'or'],['end_time','<=',time()-60,'or']])->select(['id', 'm_id', 'from', 'to', 'nonce', 'value', 'data', 'gas_price', 'gas_limit', 'sign', 'money', 'from_key', 'coin_id', 'depend','type','contract_address','order_id'])->limit(100)->get();
  102. $bnbServer=BanRPC::creatServer();
  103. foreach ($list as $value){
  104. $bnbNum=$bnbServer->getBalance($value->{'from'});
  105. if(env('TEST_SERVE')){
  106. $value->{'money'}='0.00001';
  107. }
  108. if((empty($bnbNum) || $bnbNum<($value->{'money'}+0.0004)) && !env('TEST_SERVE')){
  109. $transaction['end_time'] = time();
  110. }else{
  111. //ETH广播
  112. $send_num = Broadcast::where('from', $value->{'from'})->where('status', '2')->count('id');
  113. if ($send_num > 0) {
  114. sleep(1);
  115. continue;
  116. }
  117. $transaction = $this->sendBnb($value);
  118. if (empty($transaction) || empty($transaction['hash'])) {
  119. $transaction = ['status' => 3, 'error' => '广播失败'];
  120. } else {
  121. $transaction['status'] = 2;
  122. }
  123. if ($transaction) {
  124. Broadcast::where('id', $value->{'id'})->update($transaction);
  125. }
  126. }
  127. }
  128. return $list->count();
  129. }
  130. function sendBnb($value){
  131. $bnbServer=BanRPC::creatServer();
  132. // try {
  133. $transaction['from'] = $value['from'];
  134. $transaction['to'] = $value['to'];
  135. $transaction['chain_id'] = $bnbServer->chainId;
  136. $transaction['value'] = Utils::dec2hex(Utils::fund2int($value['money'] )); // 转账金额
  137. $transaction['data'] = '0x0';
  138. // $transaction['data'] = Utils::decodeSolMethod('transfer(address,uint256)', [$value['to'], Utils::fund2int($value['money'], 18)]);
  139. $nonce = $bnbServer->getTransactionCount($value['from']);
  140. $transaction['nonce'] = $nonce;
  141. $gas_price = $bnbServer->getGasPrice();
  142. // $transaction['gas_price'] = Utils::dec2hex(Utils::toWei("26gwei") + Utils::hex2dec($gas_price));//燃料十六进制。由eth_estimateGas获取
  143. $transaction['gas_price'] =$gas_price;//燃料十六进制。由eth_estimateGas获取
  144. $gas_limit =$this->getEthGasLimit($transaction);
  145. $transaction['gas_limit'] = $gas_limit;
  146. if($value->{'type'}==3)$value->{'m_id'}=0;
  147. $sign = $this->ethSign($transaction, PassServer::creatServer()->getSecretKey($value->{'from_key'}, $value->{'m_id'})); //交易签名
  148. $transaction['sign'] = $sign;
  149. $error='';
  150. $hash = $bnbServer->sendRawTransaction($transaction['sign'], $error);//广播交易
  151. $transaction['hash'] = $hash;
  152. return $transaction;
  153. // } catch (\Exception $e) {
  154. // return false;
  155. // }
  156. }
  157. /**
  158. * @param $transaction
  159. * @return string
  160. */
  161. public function getEthGasLimit($transaction)
  162. {
  163. $bnbServer=BanRPC::creatServer();
  164. $tx = [
  165. 'from' => $transaction['from'],
  166. 'to' => $transaction['to'],
  167. 'nonce' => $transaction['nonce'],
  168. 'value' => $transaction['value'],
  169. 'data' => $transaction['data'],
  170. 'chainId' => $bnbServer->chainId,
  171. 'gasPrice' => $transaction['gas_price'],
  172. ];
  173. $gasLimit = $bnbServer->estimateGas($tx);
  174. if (!$gasLimit) {
  175. $gasLimit = 10 * 10000; // 预估失败, 最高10万
  176. }
  177. return $gasLimit;
  178. }
  179. protected function build($from, $to, $value, $data)
  180. {
  181. $tx = [];
  182. $tx['from'] = $from;
  183. $tx['to'] = $to;
  184. $tx['value'] = $value;
  185. $tx['data'] = $data;
  186. return $tx;
  187. }
  188. function ethSign($transaction, $key)
  189. {
  190. $bnbServer=BanRPC::creatServer();
  191. $tx = [
  192. 'from' => $transaction['from'],
  193. 'to' => $transaction['to'],
  194. 'nonce' => $transaction['nonce'],
  195. 'value' => $transaction['value'],
  196. 'data' => $transaction['data'],
  197. 'chainId' => $bnbServer->chainId,
  198. 'gasPrice' => $transaction['gas_price'],
  199. 'gasLimit' => $transaction['gas_limit'],
  200. ];
  201. // 数据签名
  202. $tr = new Transaction($tx);
  203. $tr->sign($key);
  204. return Utils::fixHex($tr->serialize());
  205. }
  206. }