用到的composer包
"bitwasp/bitcoin-lib": "1.0.4",
"minter/minter-php-bip-44": "^1.0",
"web3p/ethereum-util": "^0.1.1",
"sc0vu/web3.php": "^0.1.4",
"digitaldonkey/ethereum-php": "dev-master",
"web3p/ethereum-tx": "^0.3.4"
自己封装好的类拿出来共享,是否能使用大家自行判断,使用的infura,不用自己搭建ETH
<?php
namespace app\common\library;
use BIP\BIP44;
use BitWasp\BitcoinLib\BIP39\BIP39;
use Ethereum\Ethereum;
use Web3\Providers\HttpProvider;
use Web3\RequestManagers\HttpRequestManager;
use Web3\Utils;
use Web3\Web3;
use Web3p\EthereumTx\Transaction;
use Web3p\EthereumUtil\Util;
class EtherLib
{
//protected static $eth_url = 'http://XXXXXX:8200';
protected static $eth_url = 'https://mainnet.infura.io/v3/XXX';
protected static $eth = null;
protected static $personal = null;
public static $web3 = null;
/**
* @var Ethereum
*/
public static $new_web = null;
/*
* 单例获取eth实例
*/
public static function getWeb3()
{
if (empty(self::$web3)) {
// 30 Second timeout
$timeout = 30;
self::$web3 = new Web3(new HttpProvider(new HttpRequestManager(self::$eth_url, $timeout)));
//self::$web3 = new Web3(self::$eth_url);
}
return self::$web3;
}
public static function getNewWeb3()
{
if (empty(self::$new_web)) {
self::$new_web = new Ethereum(self::$eth_url);
}
return self::$new_web;
}
/*
* 单例获取eth实例
*/
public static function getEth()
{
if (empty(self::$eth)) {
$web3 = self::getWeb3();
self::$eth = $web3->getEth();
}
return self::$eth;
}
/*
* 单例获取eth实例
*/
public static function getPersonal()
{
if (empty(self::$personal)) {
$web3 = self::getWeb3();
self::$personal = $web3->getPersonal();
}
return self::$personal;
}
/*
* 获取ETH价格
*/
public static function getEthPrice()
{
$price = cache('eth_price');
if (empty($price)) {
$info = file_get_contents('http://api.coindog.com/api/v1/currency/ranks');
if (!empty($info)) {
$info_json = json_decode($info, true);
foreach ($info_json as $item) {
if (strtoupper($item['currency']) == 'ETH') {
$price = $item['price'];
cache('eth_price', $price, ['expire' => 3600]);
}
}
} else {
$price = 0;
}
}
return $price;
}
/*
* 根据助记词导入钱包
*/
public static function import_wallet($word, $password, $callback)
{
$seed = BIP39::mnemonicToSeedHex($word, '');
$HDKey = BIP44::fromMasterSeed($seed)->derive("m/44'/60'/0'/0/0");
$util = new Util();
//生成私钥
//dump('0x' . $HDKey->privateKey);
$pub = $util->privateKeyToPublicKey($HDKey->privateKey);
$address1 = $util->publicKeyToAddress($pub);
if (!Utils::isAddress($address1)) {
$callback(0, '助记词不正确');
return;
}
$callback(1, [
'code' => 1,
'eth_address' => $address1,
'eth_private' => '0x' . $HDKey->privateKey,
'eth_seed' => $seed,
]);
/*
$account->importRawKey($HDKey->privateKey, $password,
function ($err, $data, $callback, $address1, $seed, $HDKey) {
if ($err !== null) {
//echo 'Error: ' . $err->getMessage();
$callback(0, $err->getMessage());
return;
}
$callback(1, [
'code' => 1,
'eth_address' => $address1,
'eth_private' => '0x' . $HDKey->privateKey,
'eth_seed' => $seed,
]);
});*/
//exit();
return;
}
/*
* 创建助记词
*/
public static function create_word()
{
return BIP39::entropyToMnemonic(BIP39::generateEntropy(128));
}
/*
* 创建钱包
*/
public static function create_wallet($mnemonic, $wallet_password)
{
//Get private key by path and seed
$password = '';
//$mnemonic = BIP39::entropyToMnemonic(BIP39::generateEntropy(128));
$seed = BIP39::mnemonicToSeedHex($mnemonic, $password);
$HDKey = BIP44::fromMasterSeed($seed)->derive("m/44'/60'/0'/0/0");
//dump($HDKey->publicKey);
//var_dump(strlen($HDKey->publicKey));
$util = new Util();
$pub = $util->privateKeyToPublicKey($HDKey->privateKey);
$address1 = $util->publicKeyToAddress($pub);
//$account = self::getPersonal();
//$new_web3=self::getNewWeb3();
//$new_web3->eth_call()
/* $account->importRawKey($HDKey->privateKey, $wallet_password, function ($err, $data) {
if ($err !== null) {
//echo 'Error: ' . $err->getMessage();
return;
}
// var_dump($data);exit();
});*/
return [
'eth_address' => $address1,
'eth_private' => '0x' . $HDKey->privateKey,
'eth_seed' => $seed,
];
}
/*
* 更新ETH钱包余额
*/
public static function updateBalance()
{
$u = new \app\common\model\User();
$eth = self::getEth();
$u->field('id,eth_address,eth_balance,eth_block')->whereNotNull('eth_address')->chunk(100,
function ($list) use ($eth, $u) {
foreach ($list as $item) {
$addr = $item->eth_address;
$eth->getBalance($addr, function ($err, $data) use ($addr, $u) {
if ($err !== null) {
echo 'Error: ' . $err->getMessage();
return;
}
list($bnq, $bnr) = Utils::fromWei($data, 'gwei');
$balance = $bnq->toString() / 1000000000;
$u->where(['eth_address' => $addr])->setField('eth_balance', $balance);
});
}
});
echo 'ok';
}
public static function toEther($v)
{
list($bnq, $bnr) = Utils::fromWei($v, 'gwei');
$balance = $bnq->toString() / 1000000000;
return $balance;
}
private static function getTransactionCount($from,$callback)
{
$eth = EtherLib::getEth();
$eth->getTransactionCount($from, function ($err, $data) use ($eth, $callback) {
if ($err !== null) {
$callback(0, $err->getMessage());
} else {
$callback(1, $data->toString());
}
});
}
public static function sendRawTrans($seed,$fromAccount, $toAccount,$amount,$callback ,$is_prikey=false){
if($is_prikey){
$privateKey=$seed;
}else {
$HDKey = BIP44::fromMasterSeed($seed)->derive("m/44'/60'/0'/0/0");
$privateKey = $HDKey->privateKey;
}
$eth = EtherLib::getEth();
self::getTransactionCount($fromAccount,function ($code,$nonce) use ($fromAccount,$toAccount,$amount,$eth,$privateKey, $callback) {
if($code==0){
$callback(0,$nonce);
}else{
$bnq =Utils::toWei($amount,'ether')->toString();
$gasPrice = '0x' . Utils::toWei('33', 'gwei')->toHex();
$raw=[
'from' => $fromAccount,
'to' => $toAccount,
'value' => Utils::toHex($bnq, true),
//'gas' => Utils::toHex(90000, true),
'gasLimit' => '0x76c0',
'gasPrice' => $gasPrice,//Utils::toHex(33 * 1000000000, true),
'chainId'=>1,
'nonce'=> Utils::toHex($nonce, true),
];
$txreq = new Transaction($raw);
$signed = '0x' . $txreq->sign( '0x' .$privateKey);
$eth->sendRawTransaction($signed, function ($err, $transaction) use ($eth, $callback) {
if ($err !== null) {
if ($err->getMessage() == 'insufficient funds for gas * price + value') {
$callback(0, '账户余额不足');
} else {
$callback(0, $err->getMessage());
}
return;
}
$callback(1, $transaction);
});
}
});
/* $eth->sendRawTransaction($signed, function ($err, $transaction) use ($eth, $callback) {
if ($err !== null) {
if ($err->getMessage() == 'insufficient funds for gas * price + value') {
$callback(0, '账户余额不足');
} else {
$callback(0, $err->getMessage());
}
return;
}
$callback(1, $transaction);
});*/
//echo $signed;
}
public static function sendTrans($fromAccount, $toAccount, $password, $amount, $callback)
{
$eth = EtherLib::getEth();
EtherLib::getPersonal()->unlockAccount($fromAccount, $password,
function ($err, $unlocked) use ($eth, $fromAccount, $toAccount, $callback, $amount) {
if ($err !== null) {
if ($err->getMessage() == 'could not decrypt key with given passphrase') {
$callback(0, '钱包密码不正确');
} else {
$callback(0, $err->getMessage());
}
return;
}
if ($unlocked) {
//$bnq = $amount * 1000000000;
$bnq =Utils::toWei($amount,'ether')->toString();
//$callback(0,Utils::toHex($bnq->toString(),true).'---'.$amount);
//return;
self::writeLog(json_encode([
'from' => $fromAccount,
'to' => $toAccount,
'value' => $bnq,
'gas' => 90000,
'gasPrice' => 33 * 1000000000,
]));
$eth->sendTransaction([
'from' => $fromAccount,
'to' => $toAccount,
'value' => Utils::toHex($bnq, true),
'gas' => Utils::toHex(90000, true),
'gasPrice' => Utils::toHex(33 * 1000000000, true),
], function ($err, $transaction) use ($eth, $fromAccount, $toAccount, $callback) {
if ($err !== null) {
if ($err->getMessage() == 'insufficient funds for gas * price + value') {
$callback(0, '账户余额不足');
} else {
$callback(0, $err->getMessage());
}
return;
}
$callback(1, $transaction);
});
} else {
$callback(0, '钱包密码不正确');
}
});
}
public static function writeLog($msg)
{
$file = LOG_PATH . 'eth_' . date('Ymd');
file_put_contents($file, date('Y-m-d H:i:s') . "\r\n" . $msg);
}
public static function syncOrder($address, $start_block, $end_block)
{
$host = "https://api.etherscan.io/api?module=account&action=txlist&address=$address&startblock=$start_block&endblock=$end_block&sort=asc&apikey=XXX";
$res = file_get_contents($host);
$res_json = json_decode($res, true);
if ($res_json['status'] != 0) {
return $res_json['result'];
} else {
return [];
}
}
}