用到的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 [];
        }
    }

}
最后修改:2019 年 08 月 27 日
如果觉得我的文章对你有用,请随意赞赏