Solidity学习杂记

11 篇文章 0 订阅
1 篇文章 0 订阅

收藏

数组

pragma solidity ^0.4.23;

contract Hello{

   uint[5] arr = [1,2,3,4,5];
   function Init(){
       arr[0] = 100;
       arr[2] = 200;
   }
   
   function getArr() view returns(uint[5]){
       return arr;
   }
   
   function add() view returns(uint){
       uint sum = 0;
       for(uint i = 0;i<5;i++){
           sum += arr[i]; 
       }
       return sum;
   }
}

结构体

pragma solidity ^0.4.23;

contract Hello{
        // struct 结构体里面不能包含本身,但是可以是动态长度的数组,也可是映射
    struct boy{
        uint money;
        string name;
        mapping(uint=>string) map;
    }
    boy my;  //默认为storage类型,只能够用storage类型来操作mapping
    //mapping 不能直接获取
    function init() view returns(uint,string,string){
        // boy b 是 storage 类型【在链上】  boy(1000,"zy") 是 memory类型【在内存里】 所以要转成memory才能使用 
        boy memory b = boy(1000,"zy");
        my.map[0] = "Hello";
        return(b.money,b.name,my.map[0]); 
    }
    
     //结构体作为参数必须是internal
    function test(boy memory b) internal{
    //注意 memory 到 memory是引用指针
        
    }
    function test2(boy storage b) internal{
        
    }
 
}

传址

pragma solidity ^0.4.23;

contract Hello{

    uint[] arrx;   //储存在区块链的网络上
    function test(uint[] arry) returns(uint){
        arrx = arry;  //将内存的array拷贝给区块链上的arrx
        
        //当我们在函数体内部定义了一个可变长度的数组时,实际上他默认类型是storage类型,他指向了区块链上的arrx,所以当我修改Z的元素的时候实际上我们在操作的是量上的arrx的值
        uint[] storage Z  = arrx;
        
        //通过指针实际上修改了区块量上的arrx的值
        Z[0] = 100;
        
        //修改了链上arrx的长度
        Z.length = 100;
    }
    
    function test2() returns(uint){
        return arrx[0];
    }
    
    function test3() returns(uint){
        return arrx.length;
    }
 
}

合约销毁

pragma solidity ^0.4.23;

contract Hello{
   address owner;
   constructor(){
    
     owner = msg.sender;
 }
 
 
 function kill(){
     if(msg.sender == owner){
         selfdestruct(owner);
     }
 }
 
}

继承

  • public 可以继承内外部都可以使用
pragma solidity ^0.4.23;
contract Hello{
    uint private money = 1000;   
  function echoStr() public pure returns(string){
   return 'str';
  }
  function echoExternal() external pure returns(string){
      return 'external';
      
  }
  
  function externalTest() public view returns(string){
     return this.echoExternal();
      
  }
}


contract Hello2 is Hello{

  

  function test() public view returns(string){
     return echoStr();
  }
}

  • internal 只能在继承的合约内部或合约内部使用,不能在合约的外部使用
  • external 只能用this用来外部调用 或者 Hello h = new Hello();引入调用
  • private 只能被自己使用,不能被继承
pragma solidity ^0.4.23;
contract Hello{

  function echoStr() internal pure returns(string){
   return 'str';
  }

}


contract Hello2 is Hello{

  

  function test() public view returns(string){
     return echoStr();
  }
   function test2() public view returns(string){
        return '22222';
   }
   function test3()  public view returns(string){
        return  this. echoExternal();
   }

}


contract Hello3{

        Hello h = new Hello();
        
        function externalEcho() view returns(string){
          return  h.echoExternal() ;
        }


}


modifier


pragma solidity ^0.4.23;
contract Hello{
    
    address public owner;
    
     uint public num;    
     uint lv = 10;   
     
      constructor(){
        
         owner = msg.sender;
     }
     
 
         
     modifier OnlyOwner{
         require(msg.sender == owner);  //如果不是原来的合约拥有者就停掉
         
         _;
     }
     
    modifier OwnerLv( uint _lv){
         require(lv >= _lv);  
         
         _;
     }
     
    //合约的所有者才可以修改
    function chabgeIt(uint _num) OnlyOwner OwnerLv(10){
        num = _num;
    }

}


mapping

pragma solidity ^0.4.0;
contract Hello{
    //映射
    mapping(address => uint) IdMapping;
    mapping(uint => string) NameMapping;
    
    uint public sum = 0;
    
    //防止重复注册
    modifier conrol{
           require(IdMapping[msg.sender] == 0);
           _;
    }

    function register(string name) conrol{
        address account = msg.sender;
        sum++;
        IdMapping[account] = sum;
        NameMapping[sum] = name;
        
    }
    
    function getIdByAddress(address are) view returns(uint){
        return IdMapping[are];
    }
    
        
    function getNameById(uint id) view returns(string){
        
        return NameMapping[id];
        
    }
    
}

构造函数

pragma solidity ^0.4.23;
contract Hello{
    
    uint public a;

//   function Hello(){
//       a = 100;
//   }
  
  
//   function Hello(uint _a){
//       a = _a;
//   }
   
//  constructor(){
//       a = 100;
//  }
 
 
  constructor(uint _a){

      a = _a;
 }
}

pragma solidity ^0.4.23;
contract Hello{
    
      address public owner;


 
 
  constructor(){
    
     owner = msg.sender;
 }
}

函数命名参数

pragma solidity ^0.4.23;
contract Hello{
  uint public num;
  string public name;
  
  function setData(uint _num,string _name){
      num = _num;
      name = _name;
  }
  function test(){
      setData({_name:"zy",_num:5});
  }
}

函数的重载

    函数的重载
    1,函数的名字相同
    2,函数的类型数量不同。
        参数数量不同
            function func(uint num){}
            function func(){}
        参数类型不同
            function func(uint num){}
            function func(uint8 num){}

    3,不考虑函数的返回值是否相同
    
    address 和 uint160 要注意,虽然能通过编译,但是不能够被调用( address = uint160 无法判断该调用谁)
        function func(uint160 num){}
        function func(address num){}

一些语法

pragma solidity ^0.4.0;
contract Hello{
    
    string Myname = "zy";  //    string 没有 length 属性  需要  bytes(_name).length;强转获得长度
    bool _a ;
    //  int 可正可负 int256     uint 只能正数  uint256
    int _num1 = 1 ;
    int _num2 = 200 ;
    uint _num3 = 2;
     



    /**
    * 权限     private internal external public
    * 标识符   pure constant view payable
    * view     可以自由调用,因为它只是“查看”区块链的状态而不改变它。不消耗燃料
    * pure     也可以自由调用,不写入区块链 不消耗燃料
    * payable  交易操作需要使用
    **/
    function getName() public view returns(string)
    {
        return Myname;
        
    }
    
    // 修改 消耗燃料
    function changeMyName(string _newName) public{
        Myname = _newName;
    }

    function pureTest(string _name) pure public returns(string){
        return _name;
    }
    
    
    function getBool() view public returns(bool){
        return _a;
    }
    
    
   function getBool2() view public returns(bool){
        return !_a;
    }


    function panduan() view public  returns(bool){
        return _num1 == _num2;
    }
    
    function panduan2() view public  returns(bool){
        return _num1 != _num2;
    }
    
    function yu() view public  returns(bool){
         return (_num1 == _num2) && true;
     }
        
    function huo() view public  returns(bool){
         return (_num1 == _num2)||true;
     }
     
    function add(uint a,uint b)pure public returns(uint){
         return a+b;
     }
     
     function fan() view public  returns(uint){
         return ~_num3;
     }
     
     function lyu() view public returns(int){
         return _num1<<1;
     }
     
     function flow() view public returns(uint){
         
         uint8 mm = 255;
         mm++;
         return mm;
         
     } 
     function flow2() view public returns(uint){
         
         uint8 mm = 0;
         mm--;
         return mm;
         
     } 
     
     function interTest() returns(uint){
         return 2/4*1000;
     }
     
     
     
     
     
     
    bytes1 public bynum1 = 0x7a; //    定义的时候加public会默认加个公共方法   1个字节  8位  bytes 一旦固定长度不得修改长度
        
    function getLength() returns(uint){
        return bynum1.length;
    }
    
    bytes public name = new bytes(2);
    
    function IniName(){
        name[0] = 0x7a;
        name[1] = 0x68; 
    }
    
    function getnameLength() view returns(uint){
        return name.length;
    } 
    
    function changeName(){
        name[0] = 0x88;
        
    }
    
    function changeLength(){
        name.length = 5; //设置了长度后值会右边填充0    
    }
    
    // 数组后面添加元素
    function pushtest(){
        name.push(0x99);
    }
}

payable

pragma solidity ^0.4.0;
contract Hello{
    
    address public account;  //   0x5B38Da6a701c568545dCfcB03FcB875f56beddC4  uint160
       // payable 关键字用来给合约地址充值转账
    function pay() payable{
        
    }
    
    function getBalance() view returns(uint){
        return this.balance;
    }
    
     // 获取合约地址
    function getThis() view returns(address){
        return this;
    }
    
    function getOneBalance() view returns(uint){
        address account = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
        return account.balance;
    }
    
    
      //  transfer转账 到某个账户  
    function transfer() payable{
            address account = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
            account.transfer(msg.value);
    }
    
         //  transfer转账 到合约中
    function transfer2() payable{
        
       this.transfer(msg.value);
    }
    //转账 到合约中 需要一个回滚函数,不然会报错
    function () payable{
        
    }
    
   function transfer3() payable{
            address account = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
            account.transfer(10 ether);
    }
    //send 不会报错 指会返回 true 或 false
     function sends() payable{
            address account = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
            account.send(10 ether);
    }
    
}

solstring

pragma solidity ^0.4.0;
contract Hello{
    
    string name = "zy";  //    string 没有 length 属性  需要  bytes(_name).length;强转获得长度
    string name2 = "!$%^&#@$ada";
    function getLenght() view returns(uint){
        return bytes(name).length;
    }
    function changeName() view returns (bytes1){
        return bytes(name)[1];
    }
    function getName() view returns(bytes){
        return bytes(name);
    } 
    
    function changeName2(){
        bytes(name)[0] = 'C';
    }
    
       function getLenght2() view returns(uint){
        return bytes(name2).length;
    }
}

发布测试代币

pragma solidity ^0.4.24;

// ----------------------------------------------------------------------------
// 'FIXED' 'Example Fixed Supply Token' token contract
//
// Symbol      : USDT
// Name        : USDT
// Total supply: 1,000,000,000.0000  发型代币数量 
// Decimals    : 4    小数点 
//
// Enjoy.
//
// (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. The MIT Licence.
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
// Safe maths
// ----------------------------------------------------------------------------
library SafeMath {
    function add(uint a, uint b) internal pure returns (uint c) {
        c = a + b;
        require(c >= a);
    }
    function sub(uint a, uint b) internal pure returns (uint c) {
        require(b <= a);
        c = a - b;
    }
    function mul(uint a, uint b) internal pure returns (uint c) {
        c = a * b;
        require(a == 0 || c / a == b);
    }
    function div(uint a, uint b) internal pure returns (uint c) {
        require(b > 0);
        c = a / b;
    }
}


// ----------------------------------------------------------------------------
// ERC Token Standard #20 Interface
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
// ----------------------------------------------------------------------------
contract ERC20Interface {
    function totalSupply() public constant returns (uint);
    function balanceOf(address tokenOwner) public constant returns (uint balance);
    function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
    function transfer(address to, uint tokens) public returns (bool success);
    function approve(address spender, uint tokens) public returns (bool success);
    function transferFrom(address from, address to, uint tokens) public returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}


// ----------------------------------------------------------------------------
// Contract function to receive approval and execute function in one call
//
// Borrowed from MiniMeToken
// ----------------------------------------------------------------------------
contract ApproveAndCallFallBack {
    function receiveApproval(address from, uint256 tokens, address token, bytes data) public;
}


// ----------------------------------------------------------------------------
// Owned contract
// ----------------------------------------------------------------------------
contract Owned {
    address public owner;
    address public newOwner;

    event OwnershipTransferred(address indexed _from, address indexed _to);

    constructor() public {
        owner = msg.sender;
    }

    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }

    function transferOwnership(address _newOwner) public onlyOwner {
        newOwner = _newOwner;
    }
    function acceptOwnership() public {
        require(msg.sender == newOwner);
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
        newOwner = address(0);
    }
}


// ----------------------------------------------------------------------------
// ERC20 Token, with the addition of symbol, name and decimals and a
// fixed supply
// ----------------------------------------------------------------------------
contract FixedSupplyToken is ERC20Interface, Owned {
    using SafeMath for uint;

    string public symbol;
    string public  name;
    uint8 public decimals;
    uint _totalSupply;

    mapping(address => uint) balances;
    mapping(address => mapping(address => uint)) allowed;


    // ------------------------------------------------------------------------
    // Constructor
    // ------------------------------------------------------------------------
    constructor() public {
        symbol = "USDT"; 
        name = "USDT";  //放代币名称
        decimals = 4;
        _totalSupply = (1*10**9) * 10**uint(decimals);
        balances[owner] = _totalSupply;
        emit Transfer(address(0), owner, _totalSupply);
    }


    // ------------------------------------------------------------------------
    // Total supply
    // ------------------------------------------------------------------------
    function totalSupply() public view returns (uint) {
        return _totalSupply.sub(balances[address(0)]);
    }


    // ------------------------------------------------------------------------
    // Get the token balance for account `tokenOwner`
    // ------------------------------------------------------------------------
    function balanceOf(address tokenOwner) public view returns (uint balance) {
        return balances[tokenOwner];
    }


    // ------------------------------------------------------------------------
    // Transfer the balance from token owner's account to `to` account
    // - Owner's account must have sufficient balance to transfer
    // - 0 value transfers are allowed
    // ------------------------------------------------------------------------
    function transfer(address to, uint tokens) public returns (bool success) {
        balances[msg.sender] = balances[msg.sender].sub(tokens);
        balances[to] = balances[to].add(tokens);
        emit Transfer(msg.sender, to, tokens);
        return true;
    }


    // ------------------------------------------------------------------------
    // Token owner can approve for `spender` to transferFrom(...) `tokens`
    // from the token owner's account
    //
    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
    // recommends that there are no checks for the approval double-spend attack
    // as this should be implemented in user interfaces 
    // ------------------------------------------------------------------------
    function approve(address spender, uint tokens) public returns (bool success) {
        allowed[msg.sender][spender] = tokens;
        emit Approval(msg.sender, spender, tokens);
        return true;
    }


    // ------------------------------------------------------------------------
    // Transfer `tokens` from the `from` account to the `to` account
    // 
    // The calling account must already have sufficient tokens approve(...)-d
    // for spending from the `from` account and
    // - From account must have sufficient balance to transfer
    // - Spender must have sufficient allowance to transfer
    // - 0 value transfers are allowed
    // ------------------------------------------------------------------------
    function transferFrom(address from, address to, uint tokens) public returns (bool success) {
        balances[from] = balances[from].sub(tokens);
        allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);
        balances[to] = balances[to].add(tokens);
        emit Transfer(from, to, tokens);
        return true;
    }


    // ------------------------------------------------------------------------
    // Returns the amount of tokens approved by the owner that can be
    // transferred to the spender's account
    // ------------------------------------------------------------------------
    function allowance(address tokenOwner, address spender) public view returns (uint remaining) {
        return allowed[tokenOwner][spender];
    }


    // ------------------------------------------------------------------------
    // Token owner can approve for `spender` to transferFrom(...) `tokens`
    // from the token owner's account. The `spender` contract function
    // `receiveApproval(...)` is then executed
    // ------------------------------------------------------------------------
    function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) {
        allowed[msg.sender][spender] = tokens;
        emit Approval(msg.sender, spender, tokens);
        ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data);
        return true;
    }


    // ------------------------------------------------------------------------
    // Don't accept ETH
    // ------------------------------------------------------------------------
    function () public payable {
        revert();
    }


    // ------------------------------------------------------------------------
    // Owner can transfer out any accidentally sent ERC20 tokens
    // ------------------------------------------------------------------------
    function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {
        return ERC20Interface(tokenAddress).transfer(owner, tokens);
    }
}

web3.php

  • git https://github.com/sc0Vu/web3.php/blob/master/src/Contract.php
  • 测试链
$this->web3 = new Web3('https://ropsten.infura.io/v3/8fa45462ba4d438ab7a1aff99a0787b2');
  • 测试chainId
    $this->chainId = 3;
  • 查询状态 以及日志
<?php
/**
 * Created by PhpStorm.
 * User: dee
 * Date: 2016/8/6
 * Time: 12:44
 */
namespace app\index\controller;
// use Think\Controller;

use app\index\model\User;
use \think\Request; 
use \think\Db; 
use EthTool\KeyStore;
use kornrunner\Keccak;


require('../vendor/autoload.php');
use Web3\Web3;
use EthTool\Callback;
use Web3\Contract;
use Web3\Utils;
use Web3\Providers\HttpProvider;
use Web3\Personal;
use Web3\RequestManagers\HttpRequestManager;
use EthTool\Credential;
use app\index\model\Accesscontract as Acc;


class Checktransfer {

    public $web3;

    public function __construct(){

        $this->web3 = new Web3('https://ropsten.infura.io/v3/8fa45462ba4d438ab7a1aff99a0787b2'); //测试
        
        $this->chainId = 3;

        $this->model = new \app\index\model\Waitforreceipt();

    }
    
	//  查询日志
    public function CheckLogs(){
            $hash = input('hash');
            $hash = trim($hash);

            if(empty($hash)){
                 return json(['code' => 0 ,'info'=>'缺失参数!']);
            }
            
            $type = input('types');

            $type = trim($type);
             if($type == 'eth'){
        
            $type_name = 'NewDeposit';

            }elseif ($type == 'usdt') {
           
                $type_name = 'NewDepositUSDT';

            }elseif ($type == 'xxx') {
           
                $type_name = 'NewDepositxxx';

            }else{
                return json(['code' => 0 , 'info' => '无效参数' ]);     
            }


            $model = new Acc();

            $contract = $model ->loadContract($this->web3,'xxx');//获取代币合约

            $is_hs = $model->checkEvent($contract,$type_name,$hash);
   
            if($is_hs){
                
                $is_hs['index'] -= 1;
           
                return json(['code' => 1 , 'info' =>  $is_hs]);
            }

            return json(['code' => 0 ,'info'=>'无日志信息']);
      
           
    
             // dd($receipt);
    }

    //查询订单
    public function CheckHash(){
            $hash = input('hash');
            $hash = trim($hash);

            if(empty($hash)){
                 return json(['code' => 0 ,'info'=>'缺失参数!']);
            }

            $is_hs = $this->model->saveHs($this->web3,$hash);

            if($is_hs){
                return json(['code' => 1 , 'info' =>  $is_hs]);
            }

            return json(['code' => 0 ,'info'=>'暂未上链成功']);
      
           
    
             // dd($receipt);
    }
}
<?php
namespace app\index\model;

use app\index\model\User;
use app\index\model\Apply;
use \think\Request;
use \think\Db;
use Elliptic\EC;
use kornrunner\Keccak;
use EthTool\KeyStore;

require('../vendor/autoload.php');
use Web3\Web3;
use EthTool\Callback;
use Web3\Contract;
use Web3\Utils;
use Web3\Providers\HttpProvider;
use Web3\RequestManagers\HttpRequestManager;
use app\index\controller\Index;



class Waitforreceipt
{

    public static function waitForReceipt($web3,$txhash,$timeout=60,$interval=1){


        $cb = new Callback;
        $t0 = time();
        while(true){
            $web3->eth->getTransactionReceipt($txhash,$cb);
            if($cb->result) break;
            $t1 = time();
            if(($t1 - $t0) > $timeout) break;
            sleep($interval);
        }
        return $cb->result;
    }
    /**
     * 查询哈希值一次
     * [waitForReceiptOne description]
     * @param  [type] $web3   [description]
     * @param  [type] $txhash [description]
     * @return [type]         [description]
     */
    public static function waitForReceiptOne($web3,$txhash){
        $cb = new Callback;
        // dd($txhash);
        $web3->eth->getTransactionReceipt($txhash,$cb);
        return $cb->result;
    }

    /**
     * 查询保存哈希值
     * [saveHs description]
     * @param  [type] $web3 [description]
     * @param  [type] $hash [description]
     * @return [type]       [description]
     */
    public static function saveHs($web3,$hash,$type = 0){
    $receipt = self::waitForReceiptOne($web3,$hash);
    // dd($receipt);
        try{
        	$hash = trim($hash);
        	if(!$hash){
        		return false;
        	}
            $is_hs = Db::name('eth_log_list')
                ->where('transactionHash',$hash)
                ->field('status,from,to,transactionHash')
                ->find();
          
            if($is_hs){

                $receipt = self::waitForReceiptOne($web3,$hash);

                if($is_hs['status'] == 0 && !$receipt){
                	return false;
                }
                if(!$receipt){
                    return $is_hs;
                }else{
                    $status = hexdec($receipt->status);

                    if($status == 1){
                        $save['status'] = 1;
                    }else{
                        $save['status'] = 2;
                        $save['update_time'] = time();
                    }

                    $save['blockHash'] = $receipt->blockHash;
                    $save['blockNumber'] = $receipt->blockNumber;
                    $save['contractAddress'] = $receipt->contractAddress;
                    $save['cumulativeGasUsed'] = $receipt->cumulativeGasUsed;
                    $save['from'] = $receipt->from;
                    $save['gasUsed'] = hexdec($receipt->gasUsed) * 0.00000001;
                    $save['logs'] = json_encode($receipt->logs);
                    $save['to'] = $receipt->to;

                    $save['transactionIndex'] = $receipt->transactionIndex;

                 

                    $is_hs['status'] = $save['status'];
                    Db::name('eth_log_list')
                        ->where('transactionHash',$hash)
                        ->update($save);

                    $is_hs = Db::name('eth_log_list')
    		            ->where('transactionHash',$hash)
    		            ->field('status,from,to,transactionHash')
    		            ->find();    
                    return $is_hs;
                }

            }else{
            	$save['type'] = $type;   
                $receipt = self::waitForReceiptOne($web3,$hash);
                if($receipt){
                    $status = hexdec($receipt->status);
                    if($status == 1){

                        $save['status'] = 1;
                    }else{

                        $save['status'] = 2;
                        $save['update_time'] = time();
                    }
                    $save['create_time'] = time();
                    $save['blockHash'] = $receipt->blockHash;
                    $save['blockNumber'] = $receipt->blockNumber;
                    $save['contractAddress'] = $receipt->contractAddress;
                    $save['cumulativeGasUsed'] = $receipt->cumulativeGasUsed;
                    $save['from'] = $receipt->from;
                    $save['gasUsed'] = hexdec($receipt->gasUsed) * 0.00000001;
                    $save['logs'] = json_encode($receipt->logs);
                    $save['to'] = $receipt->to;
                    $save['transactionHash'] = $receipt->transactionHash;
                    $save['transactionIndex'] = $receipt->transactionIndex;
                    Db::name('eth_log_list')->insert($save);

                    $re['status'] =  $save['status'];
                    $re['from'] = $save['from'];
                    $re['to'] = $save['to'];
                    $re['transactionHash'] = $save['transactionHash'];

                    return $re;

                }else{

                	$save['status'] = 0;
                	$save['create_time'] = time();
                	$save['transactionHash'] = $hash;
                	Db::name('eth_log_list')->insert($save);
                    return false;
                }


            }
        } catch (\Exception $e){
            return false;
        }
    }


    public static function waitForReceiptOnet($web3,$txhash){
        $cb = new Callback;
        // dd($txhash);
        $web3->eth->getTransactionReceipt($txhash,$cb);
        return $cb->result;
    }


}
<?php
namespace app\index\model;

use think\Db;

use Web3\Contract;
use Web3\Web3;
use EthTool\Callback;
use Web3\Utils;


class Accesscontract
{
    /**
     * 访问代币合约
     * @param $web3
     * @param $artifact   币种
     * @return Contract
     */
    function loadContract($web3,$artifact){
        $dir = \config('contractBuild');
        $abi = file_get_contents($dir . $artifact . '.abi');
        $addr = file_get_contents($dir . $artifact . '.addr');
        // dd($addr);
        $contract = new Contract($web3->provider,$abi);
        $contract->at($addr);

        return $contract;
    }
    /**
     * [checkEvent description] 得到事件日志
     * @param  [type] $contract [description]
     * @param  string $name     [description]  事件名字
     * @param  string $hash     [description]
     * @return [type]           [description]
     */
    function checkEvent($contract,$name='',$hash=''){

        if(!$contract|| !$name || !$hash )return false;

        try {
            $abi = $contract->abi;

            if(!$abi) return false;

            $event_arr = [];
//        拼接事件
            foreach($abi as $k => $v){
                if($v['type'] == 'event' && $name == $v['name'] ){

                    $v['checkHs'] = $v['name'].'(';
                    $arr = [];
                    foreach ($v['inputs'] as $key => $value) {
                        $arr[] = $value['type'];
                    }
                    $v['checkHs'] .= implode($arr,',').')';
                    $event_arr = $v;
                    break;

                }

            }

            if(!$event_arr) return false;

            $ethabi = $contract->ethabi;
            $mytopic = $ethabi->encodeEventSignature($event_arr['checkHs']); //得到事件hash

            $cb = new Callback;
            $contract->eth->getTransactionReceipt($hash,$cb); //得到账单
            $is_hs = $cb->result;

            if(!$is_hs)return false;

            $logs =$is_hs->logs;
            foreach ($logs as $key => $value) {

                if($value->topics){

                    if($value->topics['0'] == $mytopic){
                        $str = 	$value->data;
                        $len = mb_strlen($str);

                        if($len <= 2) return false;

                        $div = ($len-2)%64;

                        if($div) return false;
                        // dump($str);    
                        $str = mb_substr($str,2,$len);     //去除0x
                        $data_arr = str_split($str,64);
                        $re_arr = [];
                        // dump($data_arr);
                        // dd($event_arr['inputs']);
                        foreach ($event_arr['inputs'] as $i_k => $i_v) {
                            $tmp = $ethabi->decodeParameter($i_v['type'],$data_arr[$i_k]);  //解密
                            if(isset($tmp->value)){
                                $re_arr[$i_v['name']] = gmp_strval($tmp->value);
                            }else{
                                $re_arr[$i_v['name']] = $tmp;
                            }
                        }
                        return 	$re_arr;
                    }
                }
            }

        } catch (error $e) {
            return false;
        }
        return false;
    }

    /**
     * 是否部署成功
     * @param $eth
     * @param $txhash
     * @param int $timeout
     * @param int $interval
     * @return mixed
     */
    function waitForReceipt($eth,$txhash,$timeout=60,$interval=1){
        // echo 'waiting for tx receipt...' . PHP_EOL;
        $cb = new Callback;
        $t0 = time();
        while(true){
            $eth->getTransactionReceipt($txhash,$cb);
            if($cb->result) break;
            $t1 = time();
            if(($t1 - $t0) > $timeout) break;
            sleep($interval);
        }
        return $cb->result;
    }




    /**
     * 转账
     * @param $contract
     * @param $initiator
     * @param $to
     * @param $value
     * @return mixed
     */
    function transfer($contract,$initiator,$to,$value){
        $cb = new Callback;
        $opts = [
            'from' => $initiator,
            'gas' => Utils::toHex(100000,true)
        ];
        $contract->send('transfer',$to,$value,$opts,$cb);
        $txhash = $cb->result;

        $receipt = $this -> waitForReceipt($contract->eth,$txhash);

        return $receipt;
    }


    function CheckData($contract,$name){

        $cb = new Callback;
        $contract->call($name,$cb);
        return $cb->result;
    }


}	
  • 裸交易
<?php
namespace app\index\controller;

use app\index\model\User;
use app\index\model\Apply;
use \think\Request;
use \think\Db;
use Elliptic\EC;
use kornrunner\Keccak;
use EthTool\KeyStore;
use app\index\model\Accesscontract as Acc;

require('../vendor/autoload.php');
use Web3\Web3;
use EthTool\Callback;
use Web3\Contract;
use Web3\Utils;
use Web3\Providers\HttpProvider;
use Web3\RequestManagers\HttpRequestManager;
use EthTool\Credential;



class Feetransfer
{

	public $web3;

	public $admin;

	public $hyaddress;
	
	public $chainId;

	public $waitfModel;

	public $keystore;

	public $pwd;

    public function __construct(){

        $this->web3 = new Web3('https://ropsten.infura.io/v3/8fa45462ba4d438ab7a1aff99a0787b2'); //测试
        
        $this->chainId = 3;

    	$this->admin = '0x9Cx787xd5exxxxxxd6FAEf';//矿工费来源

    	$this->hyaddress = '0x510xxxxxxxx10f5xfd';  //合约地址

    	$this->waitfModel = new \app\index\model\Waitforreceipt();

    	$this->keystore = '/www/wwwroot/xxxhy/keystore/137cd6e542d6faef.json';

    	$this->pwd = 'ddd121231231';
    }



    /**
     * 释放
     * [autoWithdraw description]
     * @return [type] [description]
     */
public function autoWithdraw(){

	$cb = new Callback;

	$admin = $this->admin;//总账户地址

	$hyaddress = $this->hyaddress;

	$this->web3->eth->getBalance($admin,$cb);//转出地址余额

	$a = bcdiv($cb->result,pow(10,18),8);    //余额
	
	$val = Utils::toHex(0,true);
		
	$gasLimit = Utils::toHex(100000,true);	
   
	$point = 0.0005;//预留数量以扣除旷工费
   
	if($a <= $point ){//判断是否足够余额以转出
    //  dd($a);
		return json(['code' => 0 , 'info' =>  $admin  . ' 转出地址ETH余额不足支付矿工费']);
		exit;
	}
	
	$model = new Acc();

	$contract = $model -> loadContract($this->web3,'xxxx');//获取代币合约

	$dizhi = substr($admin,2);//截取0x之后

	$credential = Credential::fromWallet($this->pwd,$this->keystore);//获取对应json文件件

	$walletAddress = $credential->getAddress();//重新获取地址

	$this->web3->eth->getTransactionCount($walletAddress,'latest',$cb); //返回指定地址发生的交易数量
	
	$nonce =  $cb->result;

	$opts = [
		'from' => $walletAddress,
		'gas' => Utils::toHex(30000,true),
	];
		
	$contract = $model -> loadContract($this->web3,'xxxx');//获取代币合约
	
	$raw = $contract->sends('autoWithdraw',$opts,$cb);

	$raw['from'] = $walletAddress;
		
	$raw['gasPrice'] = '0x' . Utils::toWei('100','gwei')->toHex();
		
	$raw['gasLimit'] = $gasLimit;
		
	$raw['value'] = $val;
		
	$raw['nonce'] = Utils::toHex($nonce,true);
		
	$raw['chainId'] = $this->chainId;
		
	$raw['to'] = $hyaddress;

	$signed = $credential->signTransaction($raw);//获取签名

	$this->web3->eth->sendRawTransaction($signed,$cb);//发起裸交易
 
	if($cb->error){
            
		return json(['code' => 0 , 'info' => $cb->error.PHP_EOL ]);		

		}else{
			$waitfModel = $this->waitfModel;
		
			$is_save = $waitfModel->saveHs($this->web3,$cb->result,2);
		
			return json(['code' => 1 , 'info' => $cb->result ]);
	}


}

/**
 * 更新金额
 * [updateEther description]
 * @return [type] [description]
 */
public function updateMoney(){

	$num = input('num');
	$type = input('type','trim');
	if($type == 'updateEther'){
		$type_num = 3;
		$type_name = 'updateEther';
	}}else{
		return json(['code' => 0 , 'info' => '无效参数' ]);		
	}
	$cb = new Callback;

	$admin = $this->admin;//总账户地址

	$hyaddress = $this->hyaddress;

	$this->web3->eth->getBalance($admin,$cb);//转出地址余额

	$a = bcdiv($cb->result,pow(10,18),8);    //余额
	
	$val = Utils::toHex(0,true);
		
	$gasLimit = Utils::toHex(100000,true);	
   
	$point = 0.0005;//预留数量以扣除旷工费
   
	if($a <= $point ){//判断是否足够余额以转出
    //  dd($a);
		return json(['code' => 0 , 'info' =>  $admin  . ' 转出地址ETH余额不足支付矿工费']);
		exit;
	}
	
	$model = new Acc();

	$contract = $model -> loadContract($this->web3,'xxx');//获取代币合约

	$dizhi = substr($admin,2);//截取0x之后

	$credential = Credential::fromWallet($this->pwd,$this->keystore);//获取对应json文件件

	$walletAddress = $credential->getAddress();//重新获取地址

	$this->web3->eth->getTransactionCount($walletAddress,'latest',$cb); //返回指定地址发生的交易数量
	
	$nonce =  $cb->result;

	$opts = [
		'from' => $walletAddress,
		'gas' => Utils::toHex(30000,true),
	];
		
	$contract = $model -> loadContract($this->web3,'xxx');//获取代币合约
	
	$raw = $contract->sends($type_name,$num,$opts,$cb);

	$raw['from'] = $walletAddress;
		
	$raw['gasPrice'] = '0x' . Utils::toWei('100','gwei')->toHex();
		
	$raw['gasLimit'] = $gasLimit;
		
	$raw['value'] = $val;
		
	$raw['nonce'] = Utils::toHex($nonce,true);
		
	$raw['chainId'] = $this->chainId;
		
	$raw['to'] = $hyaddress;
	// dd($raw);
	$signed = $credential->signTransaction($raw);//获取签名

	$this->web3->eth->sendRawTransaction($signed,$cb);//发起裸交易
 
	if($cb->error){
            
		return json(['code' => 0 , 'info' => $cb->error.PHP_EOL ]);		

		}else{
			$waitfModel = $this->waitfModel;
		
			$is_save = $waitfModel->saveHs($this->web3,$cb->result,$type_num);
		
			return json(['code' => 1 , 'info' => $cb->result ]);
	}


}





//  导入私钥 
    public function addAdminKey($privateKey){

     	$wfn = KeyStore::save($privateKey,'asdasdas','/www/wwwroot/xxxhy/keystore');

     }



}
  • \vendor\sc0vu\web3.php\src\Contract.php 里添加sends()方法
	public function sends()
    {
        if (isset($this->functions)) {
            $arguments = func_get_args();
            $method = array_splice($arguments, 0, 1)[0];
            $callback = array_pop($arguments);

            if (!is_string($method)) {
                throw new InvalidArgumentException('Please make sure the method is string.');
            }

            $functions = [];
            foreach ($this->functions as $function) {
                if ($function["name"] === $method) {
                    $functions[] = $function;
                }
            };
            if (count($functions) < 1) {
                throw new InvalidArgumentException('Please make sure the method exists.');
            }
            if (is_callable($callback) !== true) {
                throw new \InvalidArgumentException('The last param must be callback function.');
            }

            // check the last one in arguments is transaction object
            $argsLen = count($arguments);
            $transaction = [];
            $hasTransaction = false;

            if ($argsLen > 0) {
                $transaction = $arguments[$argsLen - 1];
            }
            if (
                isset($transaction["from"]) ||
                isset($transaction["to"]) ||
                isset($transaction["gas"]) ||
                isset($transaction["gasPrice"]) ||
                isset($transaction["value"]) ||
                isset($transaction["data"]) ||
                isset($transaction["nonce"])
            ) {
                $hasTransaction = true;
            } else {
                $transaction = [];
            }

            $params = [];
            $data = "";
            $functionName = "";
            foreach ($functions as $function) {
                if ($hasTransaction) {
                    if ($argsLen - 1 !== count($function['inputs'])) {
                        continue;
                    } else {
                        $paramsLen = $argsLen - 1;
                    }
                } else {
                    if ($argsLen !== count($function['inputs'])) {
                        continue;
                    } else {
                        $paramsLen = $argsLen;
                    }
                }
                try {
                    $params = array_splice($arguments, 0, $paramsLen);
                    // print_r($params);
                    $data = $this->ethabi->encodeParameters($function, $params);
                    $functionName = Utils::jsonMethodToString($function);
                } catch (InvalidArgumentException $e) {
                    continue;
                }
                break;
            }
            if (empty($data) || empty($functionName)) {
                throw new InvalidArgumentException('Please make sure you have put all function params and callback.');
            }
            $functionSignature = $this->ethabi->encodeFunctionSignature($functionName);
            $transaction['to'] = $this->toAddress;
            $transaction['data'] = $functionSignature . Utils::stripZero($data);
			
			return $transaction;
			
 
        }
    }
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值