Contract new method.

This commit is contained in:
sc0Vu 2017-12-29 18:23:56 +08:00
parent b87e836fc5
commit b833dfebb7
2 changed files with 639 additions and 0 deletions

300
src/Contract.php Normal file
View File

@ -0,0 +1,300 @@
<?php
/**
* This file is part of web3.php package.
*
* (c) Kuan-Cheng,Lai <alk03073135@gmail.com>
*
* @author Peter Lai <alk03073135@gmail.com>
* @license MIT
*/
namespace Web3;
use InvalidArgumentException;
use Web3\Providers\Provider;
use Web3\Providers\HttpProvider;
use Web3\RequestManagers\RequestManager;
use Web3\RequestManagers\HttpRequestManager;
use Web3\Utils;
use Web3\Eth;
use Web3\Contracts\Ethabi;
use Web3\Contracts\Types\Address;
use Web3\Contracts\Types\Boolean;
use Web3\Contracts\Types\Bytes;
use Web3\Contracts\Types\Integer;
use Web3\Contracts\Types\Str;
use Web3\Contracts\Types\Uinteger;
class Contract
{
/**
* provider
*
* @var \Web3\Providers\Provider
*/
protected $provider;
/**
* abi
*
* @var array
*/
protected $abi;
/**
* constructor
*
* @var array
*/
protected $constructor = [];
/**
* functions
*
* @var array
*/
protected $functions = [];
/**
* events
*
* @var array
*/
protected $events = [];
/**
* toAddress
*
* @var string
*/
protected $toAddress;
/**
* eth
*
* @var \Web3\Eth
*/
protected $eth;
/**
* ethabi
*
* @var \Web3\Contracts\Ethabi
*/
protected $ethabi;
/**
* construct
*
* @param mixed string | Web3\Providers\Provider $provider
* @param mixed string | stdClass | array $abi
* @param string $toAddress
* @return void
*/
public function __construct($provider, $abi, $toAddress='')
{
if (is_string($provider) && (filter_var($provider, FILTER_VALIDATE_URL) !== false)) {
// check the uri schema
if (preg_match('/^https?:\/\//', $provider) === 1) {
$requestManager = new HttpRequestManager($provider);
$this->provider = new HttpProvider($requestManager);
}
} else if ($provider instanceof Provider) {
$this->provider = $provider;
}
$abi = Utils::jsonToArray($abi, 5);
foreach ($abi as $item) {
if (isset($item['type'])) {
if ($item['type'] === 'function') {
$this->functions[$item['name']] = $item;
} elseif ($item['type'] === 'constructor') {
$this->constructor = $item;
} elseif ($item['type'] === 'event') {
$this->events[$item['name']] = $item;
}
}
}
$this->abi = $abi;
if (is_string($toAddress)) {
$this->toAddress = $toAddress;
}
$this->eth = new Eth($this->provider);
$this->ethabi = new Ethabi([
'address' => new Address,
'bool' => new Boolean,
'bytes' => new Bytes,
'int' => new Integer,
'string' => new Str,
'uint' => new Uinteger,
]);
}
/**
* call
*
* @param string $name
* @param array $arguments
* @return void
*/
// public function __call($name, $arguments)
// {
// if (empty($this->provider)) {
// throw new \RuntimeException('Please set provider first.');
// }
// $class = explode('\\', get_class());
// if (preg_match('/^[a-zA-Z0-9]+$/', $name) === 1) {
// }
// }
/**
* get
*
* @param string $name
* @return mixed
*/
public function __get($name)
{
$method = 'get' . ucfirst($name);
if (method_exists($this, $method)) {
return call_user_func_array([$this, $method], []);
}
}
/**
* set
*
* @param string $name
* @param mixed $value
* @return bool
*/
public function __set($name, $value)
{
$method = 'set' . ucfirst($name);
if (method_exists($this, $method)) {
return call_user_func_array([$this, $method], [$value]);
}
return false;
}
/**
* getProvider
*
* @return \Web3\Providers\Provider
*/
public function getProvider()
{
return $this->provider;
}
/**
* setProvider
*
* @param $provider
* @return bool
*/
public function setProvider($provider)
{
if ($provider instanceof Provider) {
$this->provider = $provider;
return true;
}
return false;
}
/**
* getFunctions
*
* @return array
*/
public function getFunctions()
{
return $this->functions;
}
/**
* getEvents
*
* @return array
*/
public function getEvents()
{
return $this->events;
}
/**
* getConstructor
*
* @return array
*/
public function getConstructor()
{
return $this->constructor;
}
/**
* getAbr
*
* @return array
*/
public function getAbi()
{
return $this->abi;
}
/**
* getEth
*
* @return \Web3\Eth
*/
public function getEth()
{
return $this->eth;
}
/**
* new
* Deploy a contruct with params.
*
* @param mixed
* @return void
*/
public function new()
{
if (isset($this->constructor)) {
$constructor = $this->constructor;
$arguments = func_get_args();
$callback = array_pop($arguments);
if (count($arguments) < count($constructor['inputs'])) {
throw new InvalidArgumentException('Please make sure you have put all constructor params and callback.');
}
if (is_callable($callback) !== true) {
throw new \InvalidArgumentException('The last param must be callback function.');
}
$params = array_splice($arguments, 0, count($constructor['inputs']));
$data = $this->ethabi->encodeParameters($constructor, $params);
$transaction = [];
if (count($arguments) > 0) {
$transaction = $arguments[0];
}
$transaction['to'] = '';
$transaction['data'] = $data;
$this->eth->sendTransaction($transaction, function ($err, $transaction) use ($callback){
if ($err !== null) {
return call_user_func($callback, $err, null);
}
return call_user_func($callback, null, $transaction);
});
}
}
}

339
test/unit/ContractTest.php Normal file
View File

@ -0,0 +1,339 @@
<?php
namespace Test\Unit;
use Test\TestCase;
use Web3\Contract;
class ContractTest extends TestCase
{
/**
* contract
*
* @var \Web3\Contract
*/
protected $contract;
/**
* testAbi
* GameToken abi from https://github.com/sc0Vu/GameToken
*
* @var \Web3\Contract
*/
protected $testAbi = '[
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"name": "",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "standard",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "address"
},
{
"name": "",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "initialSupply",
"type": "uint256"
},
{
"name": "tokenName",
"type": "string"
},
{
"name": "decimalUnits",
"type": "uint8"
},
{
"name": "tokenSymbol",
"type": "string"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "from",
"type": "address"
},
{
"indexed": true,
"name": "to",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
}
]';
/**
* accounts
*
* @var array
*/
protected $accounts;
/**
* setUp
*
* @return void
*/
public function setUp()
{
parent::setUp();
// $this->contract = new Contract('http://localhost:8545', $this->testAbi);
$this->contract = new Contract($this->web3->provider, $this->testAbi);
$this->contract->eth->accounts(function ($err, $accounts) {
if ($err === null) {
if (isset($accounts->result)) {
$this->accounts = $accounts->result;
return;
}
}
});
}
/**
* testDeploy
*
* @return void
*/
public function testDeploy()
{
$contract = $this->contract;
// var_dump($this->contract->constructor);
if (!isset($this->accounts[0])) {
$account = '0x407d73d8a49eeb85d32cf465507dd71d507100c1';
} else {
$account = $this->accounts[0];
}
$contract->new(10000, 'Game Token', 1, 'GT', [
'from' => $account
], function ($err, $result) use ($contract) {
if ($err !== null) {
// infura api gg
return $this->assertTrue($err !== null);
}
if ($result->result) {
echo "\nTransaction has made:) id: " . $result->result . "\n";
}
$transactionId = $result->result;
$this->assertTrue((preg_match('/^0x[a-f0-9]{64}$/', $transactionId) === 1));
$contract->eth->getTransactionReceipt($transactionId, function ($err, $transaction) {
if ($err !== null) {
return $this->fail($err);
}
if ($transaction->result) {
echo "\nTransaction has mind:) block number: " . $transaction->result->blockNumber . "\n";
}
});
});
}
}