You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

242 lines
8.2 KiB

<?php
namespace App\Services\CoinService;
use App\Libs\Ethtool\Callback;
use App\Services\CoinService\Interfaces\CoinServiceInterface;
use GuzzleHttp\Client;
use phpseclib\Math\BigInteger as BigNumber;
use Web3\Eth;
use Web3\Personal;
use Web3\Providers\HttpProvider;
use Web3\RequestManagers\HttpRequestManager;
use Web3\Utils;
use Web3\Web3;
class GethService implements CoinServiceInterface
{
public $web3;
public $eth;
public $personal;
private $provider;
private $apikey = 'cfaf58162bea2da0b03e76e2dd64207a06b27233779d5cc25176a92e0973';
private $password = 'withdr343e3w';
private $gwei = '90';
private $gas = 60000;
public function __construct()
{
$this->password = config('coin.geth_pwd');
$this->provider = config('coin.geth_host');
$this->web3 = new Web3(new HttpProvider(new HttpRequestManager($this->provider, 30)));
$this->personal = new Personal($this->provider);
$this->eth = new Eth($this->provider);
}
public function weiToEther($value)
{
list($bnq, $bnr) = Utils::fromWei($value, 'ether');
// 后面部分舍去
$power = pow(10, 5); // 保留5位小数
$bnr_num = floor($bnr->toString() / pow(10, 18) * $power) / $power;
return $result = $bnq->toString() + $bnr_num;
}
public function getBalance($account)
{
$this->web3->eth->getBalance($account, function ($err, $data) use (&$result) {
if ($data) {
return $result = $this->weiToEther($data);
}
return $result = -1;
});
return $result;
}
public function listAccounts()
{
$this->web3->personal->listAccounts(function ($err, $account) use (&$accountList) {
if ($err !== null) {
// do something
$accountList = 0;
return 0;
}
$accountList = $account;
});
return $accountList;
}
public function getTransaction($transactionId)
{
// TODO: Implement getTransaction() method.
}
public function newAccount()
{
$password = $this->password;
return $this->interactiveEth('personal_newAccount', [$password]);
}
/*直接用guzzlehttp与以太坊交互*/
public function interactiveEth($method, array $params)
{
$opts = [
'json' => [
'jsonrpc' => '2.0',
'method' => $method,
'params' => $params,
'id' => time()
]
];
$rsp = (new Client())->post($this->provider, $opts);
if (isset(\GuzzleHttp\json_decode($rsp->getBody())->error)) return 0;
return \GuzzleHttp\json_decode($rsp->getBody())->result;
}
/*转账交易
参数1:转出账户
参数2:转入账户
参数3:数量 单位为eth
参数4:密码
参数5:gaslimit 参数6:gasprice 单价 单位为gwei
*/
public function sendTransaction($from, $to, $value, $gas = null, $gasPrice = null)
{
if (blank($gasPrice)) {
// $gasPrice = $this->interactiveEth('eth_gasPrice',[]);
$gasPrice = Utils::toHex(Utils::toWei($this->getEthGasPrice('fast'), 'Gwei'), true);
}
if (blank($gas)) {
$gas = $this->getGasUse();
}
$password = $this->password;
$value = "0x" . base_convert(bcmul($value, '1000000000000000000', 0), 10, 16);
// nonce
$cb = new Callback;
$this->eth->getTransactionCount($from, 'latest', $cb);
$nonce = $cb->result;
$nonce = $nonce->toString();
$transaction = [[
"from" => $from,
"to" => $to,
"gas" => $gas,
"gasPrice" => $gasPrice,
"value" => $value,
"data" => "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675",
'nonce' => $nonce == 0 ? '0x0' : Utils::toHex($nonce, true),
], "{$password}"];
// $transaction = [[
// "from"=>"0x7b8172e885fba4f0fd593ede603c067a7fb17971",
// "to"=>"0x3c119f11ea139cc9432cc07d79d239c31acbb857",
// "gas"=>"0x76c0",
// "gasPrice"=>"0x9184e72a000",
// "value"=>"0x1",
// "data"=>"0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675",
// ],"123456"];
return $this->interactiveEth('personal_sendTransaction', $transaction);
}
// 代币归集时 发送代币交易手续费
public function sendFee($address)
{
$eth_fee_account = \App\Models\CenterWallet::query()->where('center_wallet_account', 'eth_fee_account')->value('center_wallet_address');
if (blank($eth_fee_account)) return false;
// $gasPrice = $this->interactiveEth('eth_gasPrice',[]);
$gasPrice = Utils::toHex(Utils::toWei($this->getEthGasPrice('fast'), 'Gwei'), true);
$gas = $this->getGasUse();
$password = $this->password;
$fee = new BigNumber((hexdec($gasPrice) * hexdec($gas)));
$send_value = Utils::toHex($fee, true);
// nonce
$cb = new Callback;
$this->eth->getTransactionCount($eth_fee_account, 'latest', $cb);
$nonce = $cb->result;
$nonce = $nonce->toString();
$transaction = [[
"from" => $eth_fee_account,
"to" => $address,
"gas" => $gas,
"gasPrice" => $gasPrice,
"value" => $send_value,
"data" => "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675",
'nonce' => $nonce == 0 ? '0x0' : Utils::toHex($nonce, true),
], "{$password}"];
return $this->interactiveEth('personal_sendTransaction', $transaction);
}
// 归集
public function collection($from, $to, $value)
{
// $gasPrice = $this->interactiveEth('eth_gasPrice',[]);
$gasPrice = Utils::toHex(Utils::toWei($this->getEthGasPrice('fast'), 'Gwei'), true);
$gas = $this->getGasUse();
$password = $this->password;
$a = new BigNumber(Utils::toWei((string)$value, 'ether')->toString());
$b = new BigNumber((hexdec($gasPrice) * hexdec($gas)));
$send_value = Utils::toHex($a->subtract($b), true);
// nonce
$cb = new Callback;
$this->eth->getTransactionCount($from, 'latest', $cb);
$nonce = $cb->result;
$nonce = $nonce->toString();
$transaction = [[
"from" => $from,
"to" => $to,
"gas" => $gas,
"gasPrice" => $gasPrice,
"value" => $send_value,
"data" => "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675",
'nonce' => $nonce == 0 ? '0x0' : Utils::toHex($nonce, true),
], "{$password}"];
return $this->interactiveEth('personal_sendTransaction', $transaction);
}
/**
* 以太坊网络上的快速,标准和安全的低汽油价格
*/
public function getEthGasPrice($t = 'average')
{
// $url = 'https://data-api.defipulse.com/api/v1/egs/api/ethgasAPI.json?api-key=' . $this->apikey;
$url = 'https://ethgasstation.info/api/ethgasAPI.json?api-key=' . $this->apikey;
$rsp = (new Client())->get($url);
if (isset(\GuzzleHttp\json_decode($rsp->getBody())->error)) return $this->gwei;
$data = \GuzzleHttp\json_decode($rsp->getBody());
if ($t == 'average') {
if (!isset($data->average)) return $this->gwei;
$average = $data->average / 10;
return $average > $this->gwei ? $this->gwei : (string)$average;
} else {
if (isset($data->fast)) {
$fast = $data->fast / 10;
return $fast > $this->gwei ? $this->gwei : (string)$fast;
}
return $this->gwei;
}
}
// 获取交易预估gas用量
public function getGasUse($estimate = false, $transaction = [])
{
if ($estimate) {
return Utils::toHex($this->gas, true);
} else {
$gas = $this->interactiveEth('eth_estimateGas', $transaction);
return $gas ?: Utils::toHex($this->gas, true);
}
}
}